“正常”的 TCP 握手如下所示:
MachineA → SYN → MachineB
Machine B → SYN,ACK → MachineA
MachineA → ACK → MachineB
这意味着对于每个步骤,都需要在数据包中设置一个标志(或一组标志)。
当存在预期标志时,是否会丢弃额外的标志,或者是否将带有额外标志的数据包视为不正确?换句话说,以下序列是否会被视为MachineB
完整、正确的握手?
MachineA → SYN → MachineB
Machine B → SYN,ACK → MachineA
MachineA → ACK,RST,FIN → MachineB
ACK
存在于最后一个数据包中(因此握手可以看作是完成的),但也有一个RST
andFIN
标志(这只是无关标志的一个例子)。
我的问题很笼统 - 初次握手只是一个例子,我对丢弃或不在其他序列上使用额外标志的一般情况也很感兴趣。
答案1
从技术上讲,它们本身都不是多余的,即使您示例中的完整组合确实过多。
“握手的第三个数据包需要 ACK”是一种过于简单的说法——TCP 握手实际上从未被指定为具有这种严格的
SYN
→ SYN,ACK
→ACK
形式。相反,每个标志都有特定的功能和特定的状态转换,导致典型的握手方式如下。
更一般地,握手的功能是:
- 机器 A 发送
SYN
,机器 BACK
发送 。 - 机器 B 发送
SYN
,机器 AACK
则发送 。 - 当双方都确认了对方的初始 SYN 数据包时,连接就建立了。
即使ACK
机器 B 与 合并SYN
,这些仍然只是单独的操作,甚至规范也将其描述为逻辑上的四次握手,其中一些步骤“可以组合“变成三方联盟——通常是,但这也不是一成不变的。
例如,两个主机可以
SYN
同时发送 s,交叉路径(我认为在实践中不会发生这种情况),从而导致SYN
⇄SYN
/SYN,ACK
⇄SYN,ACK
交换 - 称为“同时打开“在 TCP 中。另一方面,虽然规范确实规定收到 SYN 后应发送 SYN,ACK 作为回应,但如果只是在第二步中收到了一个
ACK
无 ACKSYN
——尽管它对推进握手没有影响,但它是一个有效的 ACK。
同样地,FIN
→→序列由两个不同的→序列组成FIN,ACK
,其中每台机器都确认收到的FIN,这是合法的——ACK
FIN
ACK
和常见的- 有一个 ”半闭“连接中,一端发出了 FIN,但另一端仅仅确认了 ACK,但继续发送数据。
关于你的例子:
当机器 B 收到第 3 个数据包时,它处于 SYN-RECEIVED 状态。
这是被允许
RST
此时已经设置,这将关闭连接而不完全建立它 - 不是作为无效的握手数据包,而是作为有效的 RST。规范并未说明此时是否检查 FIN —— 只有在没有 RST 的情况下才会进行检查。
也是允许此时进行
FIN
设置,如果没有 RST 则会产生与连接处于 ESTABLISHED 状态相同的效果。(请注意,同一节仅说“发送对 FIN 的确认”;它没有提到发送另一个 FIN 作为回复 - 这必须由关闭套接字的软件明确完成。)
拥有两个都同一个数据包上的 FIN 和 RST 确实很奇怪,但在这种情况下 RST 将首先生效,并且(按照规范中详述的算法)FIN 将永远不会被检查。
我的问题很笼统 - 初次握手只是一个例子,我对丢弃或不在其他序列上使用额外标志的一般情况也很感兴趣。
没有“额外标志”的一般情况;规范列出了接收器的标志应该检查每个州,响应取决于标志和状态。例如,在 CLOSING 状态下,URG 标志指定为“忽略 URG”,而在 SYN-SENT 状态下,则按常规处理(因为 SYN 数据包允许包含常规数据)。