TCP的连接和终止——三次握手、四次挥手

连接

简要过程

TCP的连接和终止——三次握手、四次挥手_第1张图片

A:发送SYN请求 告诉B "我要连接了"
B:SYN、ACK ack = x+1,告诉A "哦 我知道了,你能听到我的话"
A:ACK 告诉B "可以听到!我要发数据了!!"


A在发送ACK后,进入ESTABLISHED,B在接受到ACK后进入ESTABLISHED

为什么这样设计

保持通信双方的信息对称,使通信双方处于同步状态

保证双方都能发数据,也能收数据。如果当初的TCP设计的是两次握手,

  • A发送SYN,B接收到 返回对A请求的确认,自身进入ESTABLISHED状态,A收到,进入ESTABLISHED (ok)
  • A发送SYN,B接收到 返回对A请求的确认,自身进入ESTABLISHED状态,[SYN ACK]由于网络原因,而停滞。A以为SYN发送失败,则重传一个SYN,此时B再返回[SYN ACK],A收到,双方都进入ESTABLISHED ,进行传输数据。假设此连接在通信结束后,释放连接资源,而此时第一次在网络停滞但未被丢弃的SYN包抵达了,B又进入ESTABLISHED,而此时A已经CLOSE,B一直没有释放连接资源,苦苦等待,因此浪费了资源。

假设四次握手的过程是这样:

  • A->B SYN
  • B->A ACK
  • B->A SYN
  • A->B ACK
    中间二三步可以合并一起,B既确认A(表示能收),发ACK给B,试试能不能发,四次没有必要,三步就可以确保双方的收发,建立连接。

知乎上看到的:

三次握手这个说法不好,其实是双方各一次握手,各一次确认,其中一次握手和确认合并在一起

终止

简要过程

TCP的连接和终止——三次握手、四次挥手_第2张图片
  • A主动关闭方,B被动关闭方
  • A放送[FIN] 一个中断请求给B,"我要关闭啦!!!"
  • B收到FIN,发送ACK,告诉A,"我知道了你要关闭了,你还需要等我下,可能还有要发送的数据",通知应用程序。
  • A收到 进入FIN_WAIT_1
  • B进入CLOSE_WAIT状态(被动关闭),已经没有要发送的工作了,发送一个[FIN ACK],"我没什么要发的,可以关闭啦"
  • A收到进入FIN_WAIT_2,此时也得发送一个ACK确认,"收到了你的关闭请求",进入TIME_WAIT状态,等待一个2MSL时间
  • B收到了ACK,进入CLOSED,A在2MSL的时间段内没有收到FIN,确保最后一次ACK发送到B,这下放心地关闭了

为什么要这样设计

设置TIME_WAIT的原因

MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。

假设最终的 ACK 丢失 , server 将重发 FIN , client 必须维护 TCP 状态信息以便可以重发最终的 ACK ,否则会发送RST ,结果 server 认为发生错误。

若要TCP可靠地终止连接的两个方向 ( 全双工关闭 ) , client 必须进 TIME_WAIT状态。

现在我们考虑终止连接时的被动方发送了一个FIN,然后主动方回复了一个ACK,然而这个ACK可能会丢失,这会造成被动方重发FIN,这个FIN可能会在互联网上存活MSL。

如果没有TIME_WAIT的话,假设连接1已经断开,然而其被动方最后重发的那个FIN(或者FIN之前发送的任何TCP分段)还在网络上,然而连接2重用了连接1的所有的5元素(源IP,目的IP,TCP,源端口,目的端口),刚刚将建立好连接,连接1迟到的FIN到达了,这个FIN将以比较低但是确实可能的概率终止掉连接2。

摘录他人

摘自知乎的一段
作者:车小胖
链接:https://www.zhihu.com/question/67013338/answer/248375813

TCP四次挥手也遵循相似的套路。
主动断开的一侧为A,被动断开的一侧为B。

  • 第一个消息:A发FIN
  • 第二个消息:B回复ACK
  • 第三个消息:B发出FIN

此时此刻:B单方面认为自己与A达成了共识,即双方都同意关闭连接。此时,B能释放这个TCP连接占用的内存资源吗?不能,B一定要确保A收到自己的ACK、FIN。所以B需要静静地等待A的第四个消息的到来:

  • 第四个消息:A发出ACK,用于确认收到B的FIN

当B接收到此消息,即认为双方达成了同步:双方都知道连接可以释放了,此时B可以安全地释放此TCP连接所占用的内存资源、端口号。

所以被动关闭的B无需任何wait time,直接释放资源。

但,A并不知道B是否接到自己的ACK,A是这么想的:
1)如果B没有收到自己的ACK,会超时重传FiN那么A再次接到重传的FIN,会再次发送ACK
2)如果B收到自己的ACK,也不会再发任何消息,包括ACK

无论是1还是2,A都需要等待,要取这两种情况等待时间的最大值,以应对最坏的情况发生,这个最坏情况是:

去向ACK消息最大存活时间(MSL) + 来向FIN消息的最大存活时间(MSL)。

这恰恰就是2MSL( Maximum Segment Life)。

等待2MSL时间,A就可以放心地释放TCP占用的资源、端口号,此时可以使用该端口号连接任何服务器。

为何一定要等2MSL?如果不等,释放的端口可能会重连刚断开的服务器端口,这样依然存活在网络里的老的TCP报文可能与新TCP连接报文冲突,造成数据冲突,为避免此种情况,需要耐心等待网络老的TCP连接的活跃报文全部死翘翘,2MSL时间可以满足这个需求(尽管非常保守)!

你可能感兴趣的:(TCP的连接和终止——三次握手、四次挥手)