TCP的四次挥手

1、概述

四次挥手是浏览器和服务器断开连接的一种方式,目的是断开连接,结束数据传输的过程。

第一次挥手:浏览器告诉服务器,我的数据传输完了,我要断开连接了。

第二次挥手:服务器告诉浏览器,好的我知道你要断开连接了,但我还有数据没传完,我传完再告诉你。

第三次挥手:服务器的数据传完了,告诉浏览器自己也要断开连接了。

第四次挥手:浏览器告诉服务器,我收到了你的两次挥手报文,可以成功断开。

至此,双方数据都传输完了,并知道对方做好了断开连接的准备,也知道对方知道自己的情况。可以正式断开了。


2、具体过程

image

参数说明

FIN:

  • TCP报文中的标志位字段之一。
  • 标记数据是否发送完毕。如果 FIN=1,表示数据已经发送完成,可以释放连接。

ACK:

  • TCP报文中的标志位字段之一。
  • 表示前面的确认号字段是否有效,ACK=1 时表示有效。只有当 ACK=1 时,前面的确认号字段才有效。
  • TCP 规定,连接建立后,ACK 必须为 1。

1、主动关闭方发送FIN连接释放报文段

客户端调用 close 方法,告诉服务器自己要主动关闭连接,会发送一个 FIN 报文给服务端,客户端进入FIN-WAIT-1状态。

  • 半关闭半连接
    • 客户端发送 FIN 包以后不能再发送数据给服务端,但是还可以接受服务端发送的数据,这个状态就是半关闭
    • 而三次握手中服务器收到SYN报文时的连接即为半连接

2、被动关闭方发送对FIN的ACK普通确认报文段

由于此时服务器数据很可能还没有发完,需要继续向客户端发送未完成的数据,又不能让客户端等太久,所以先向客户端发送ACK 确认报文段,服务端进入 CLOSE_WAIT,客户端收到ACK之后进入FIN-WAIT-2状态。

3、被动关闭方发送FIN连接释放报文

当服务器数据发送完毕之后。发送 FIN 报文给客户端,然后进入LAST-ACK 状态,等待客户端的 ACK。

4、主动关闭方发送对FIN的ACK普通确认报文段

客户端收到服务端的 FIN 报文以后,回复 ACK 报文,随后进入TIME_WAIT状态(主动关闭连接的一方才有 TIME_WAIT 状态)。

等待 2 个 MSL (MSL:最长报文段寿命)以后进入 CLOSED状态。

服务端收到 ACK 以后进入CLOSED状态。正常情况下服务器结束TCP连接的时间要比客户端早一些。


3、为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候,实际是把四次握手优化为了三次。

而关闭连接时无法优化为三次,原因如下:

服务器收到对方的FIN报文时,很可能还有数据没发完,需要等到数据发送完毕之后才向客户端发送FIN报文,但是又不能让客户端等太久,就先发ACK告诉客户端我收到了你的FIN释放连接请求,客户端收到ACK之后便不会重复发送断开连接的请求。

等到服务器数据传输完毕后,才会发FIN释放连接报文。

另外,如果服务端确定没有数据需要发给客户端,那么当然是可以把 FIN 和 ACK 合并成一个包,四次挥手的过程就成了三次。


4、为什么 TIME_WAIT 等待的时间是 2MSL?

什么是MSL?

MSL(Maximum Segment Lifetime),报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

为什么是2MSL?

设置成2MSL可以保证两点:

  • 1、保证服务端的连接能够正确关闭
    • 客户端是发出了第四次挥手的报文后进入的TIME_WAIT,如果第四次握手中,客户端发给服务器的ACK报文丢失了,服务器就会超时重发 FIN报文给客户端。
    • 客户端要保证极端情况下也能接受到服务器的超时重发FIN报文,然后给服务器重传第四次握手报文,确保服务器能正常关闭。
  • 2、防止收到历史数据,从而导致数据错乱的问题
    • 客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的历史数据。

5、数据包丢失

第一次挥手丢失了,会发生什么?

客户端重传 FIN 报文,超过阈值之后进入close 状态。

第二次挥手丢失了,会发生什么?

第二次挥手发的是ACK 报文,ACK 报文是不会重传的。

所以如果服务端的第二次挥手丢失了,还是客户端这边超时重传第一次挥手的FIN 报文,直到收到服务端的第二次挥手的ACK报文,或者达到最大的重传次数进入close状态。

第三次挥手丢失了,会发生什么?

服务端重发 FIN 报文,超过阈值之后进入close 状态。

第四次挥手丢失了,会发生什么?

同样的。第四次挥手的ACK不会重传,所以服务端会重传FIN。

如果客户端在2MSL时间内能收到重传FIN,则客户端可以重传ACK,否则客户端关闭,服务端也会在重传FIN达到一定次数之后关闭。

客户端在收到第三次挥手的FIN 报文之后,再次收到服务端的数据包会怎么处理?

客户端如果收到乱序的 FIN 报文,会将FIN包加入到「乱序队列」,并不会进入到 TIME_WAIT 状态。
等收到前面被网络延迟的数据包时,重组报文得到完整顺序的数据包之后,发现有 FIN 标志,这时才会进入 TIME_WAIT 状态。

客户端在 TIME_WAIT 状态下收到服务端的数据包会怎么处理?

客户端会发送该数据包的 ACK 确认报文,然后丢掉该数据包。


学习参考:

posted @ 2022-11-21 11:41  笔下洛璃  阅读(142)  评论(0编辑  收藏  举报