为什么TCP连接终止需要四次握手?

34
当建立连接时,有以下步骤:

客户端 ------SYN----> 服务器

客户端 <---ACK/SYN---- 服务器 ----①

客户端 ------ACK----> 服务器

当终止连接时,有以下步骤:

客户端 ------FIN----> 服务器

客户端 <-----ACK------ 服务器 ----②

客户端 <-----FIN------ 服务器 ----③

客户端 ------ACK----> 服务器

我的问题是:为什么不能像①那样在同一个数据包中设置②和③,即在一个数据包中同时发送ACK和FIN?

8
允许半开放式连接? - Some programmer dude
@Someprogrammerdude 我从这个链接学到了这个知识点:https://networkengineering.stackexchange.com/questions/24068/why-do-we-need-a-3-way-handshake-why-not-just-2-way?newreg=531924225dc8452ebd9bbb93a01db9ef - touchstone
顶部答案说ACK和SYN在同一个数据包中设置,那么我想为什么终止不能在一个数据包中设置ACK和FIN,以减少一次握手。 - touchstone
1
它可以,有时候确实会这样。 - user207421
尝试这个答案:https://networkengineering.stackexchange.com/questions/38805/why-is-the-last-ack-needed-in-tcp-four-way-termination - Andrejs
6个回答

35

在经过大量搜索后,我意识到四次挥手实际上是两个双向握手。

如果终止是真正的四次操作,则2和3确实可以在同一个数据包中设置为1。

但这是一个两阶段的工作:第一阶段(即第一个双向握手)如下:

Client ------FIN-----> Server

Client <-----ACK------ Server

此时,客户端处于FIN_WAIT_2状态,等待来自服务器的FIN。作为双向的全双工协议,现在一个方向已经断开连接,不再发送数据,但是接收仍然可用,客户端必须等待另一个“半双工”终止。

当服务器发送FIN到客户端时,客户端会响应一个ACK来终止连接。

总结:2和3不能合并成一个包,因为它们属于不同的状态。但是,如果服务器在收到客户端的FIN时没有更多的数据或根本没有数据要发送,则可以将2和3合并成一个包。

参考文献:

  1. http://www.tcpipguide.com/free/t_TCPConnectionTermination-2.htm
  2. http://www.tcpipguide.com/free/t_TCPConnectionEstablishmentProcessTheThreeWayHandsh-3.htm
  3. http://www.tcpipguide.com/free/t_TCPOperationalOverviewandtheTCPFiniteStateMachineF-2.htm

5
这意味着当客户端处于FIN_WAIT_2状态时,服务器可以向客户端发送更多真实的数据,因为连接现在是单向传输的吗?然后一旦它发送完所有数据,就可以向客户端发送第二个FIN了? - Sush
为什么没有FIN-ACK?就像SYN-ACK一样,但是用于关闭。 - Vinigas
如果服务器在收到客户端的FIN时没有更多数据或根本没有数据需要发送,则可以将2和3合并为一个数据包。是否有任何RFC提到这一点? - kkkkgyg

14

我认为2和3在技术上当然可以合并,但是不够灵活因为它们不是原子性的。
第一个FIN1 C到S仅表示:我将关闭我的通信方式。 第一个ACK1 S到C表示对FIN1的响应。好的,我知道你的通道已经断开,但对于我的S(服务器)连接方式,我还不确定。也许我的接收缓冲区尚未完全处理。我需要的时间是不确定的。 因此,2和3不适合合并。只有服务器才有权决定何时可以断开他的连接方式。


到目前为止最好的解释。用一个清晰的例子真正深入了解了“为什么”。 - Weipeng

4
从维基百科 - "还可以通过三次握手来终止连接,当主机A发送FIN时,主机B回复FIN和ACK(仅将两个步骤合并为一个),然后主机A回复ACK。[14]"
来源:
维基百科 - https://en.wikipedia.org/wiki/Transmission_Control_Protocol [14] - Tanenbaum,Andrew S.(2003-03-17)。计算机网络(第四版)。Prentice Hall。ISBN 0-13-066102-3。

这很特别...嗯,在这种情况下,FIN和ACK位是否都在一个数据包中设置?那么状态转移应该是什么?我的意思是FIN_WAIT2阶段(客户端)和CLOST_WAIT阶段(服务器端)是否仍然存在? - touchstone

4
根据这份文档,我们可以看到四次握手的详细过程如下图所示。

enter image description here

TCP堆栈会自动发送ACK数据包(标记为②)。应用程序调用close套接字API控制下一个FIN数据包(标记为③)来结束连接。应用程序有权终止连接。因此在一般情况下,我们不将这两个数据包合并成一个。
相反,在TCP连接建立阶段,ACK/SYN数据包(标记为①)会由TCP堆栈自动发送。该过程简单易行,因此TCP堆栈默认处理。

-1

如果从编码的角度来看,拥有4种方式比3种更合理,尽管两者都可以使用。

当一方要终止连接时,对等方可能有多种可能性或状态。至少有一种是正常的,一种是在传输或接收中,一种是在此启动之前突然处于断开状态。

终止的方式应该考虑到以上三种情况,因为它们在现实生活中都有很高的发生概率。

因此,基于以上原因更容易找出原因。如果对等方处于离线状态,则客户端可以通过深入过程中捕获的数据包内容来推断对等方状态,因为无法从对等方接收到第一个确认消息。但是,如果将两个消息组合在一起,则客户端很难知道对等方不响应的原因,因为不仅离线状态可能导致数据包丢失,而且服务器端处理过程中的各种异常也可能导致这种情况发生。更不用说客户端需要等待大量时间直到超时。通过额外的1条消息,这两个问题可以更容易地从客户端方面处理。

之所以看起来像编码,是因为消息中包含的信息就像代码日志一样。


-2
三次握手连接设置)中: 服务器必须确认 (ACK) 客户端的 SYN,同时服务器也必须发送自己的 SYN,包含服务器将在连接上发送的数据的初始序列号。 因此服务器会在一个单独的段中发送它的 SYN 和客户端的 SYNACK
在连接终止时: 需要四个分段才能终止连接,因为每个方向都需要发送FINACK
(2)表示接收到的第一个分段FIN已被TCP确认(ACK)。
(3)表示随后接收到文件结尾的应用程序将关闭其套接字。 这导致其TCP发送FIN
然后最后一个分段意味着接收此最终FIN的系统上的TCP确认(ACK)了FIN

32
你刚刚在问题中对他的形象进行了改述。这仅仅解释了TCP终止,却并没有“解释”为什么会发生TCP终止。请翻译以上内容。 - deppfx
2
@deppfx,然而,我认为“一段时间后”这个短语对我来说已经很清楚了。 - Wason
@deppfx 有时候服务器需要休息一下才能结束。 我认为4路更加灵活。在设置阶段不需要等待时间。 - Wason
这并没有解释太多,只是重新表述问题,请在回答时清晰明了。 - melvil james
为什么没有FIN-ACK呢?就像SYN-ACK一样,但是用于关闭。 - Vinigas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接