有握手就有挥手,上篇讲了 TCP的三次握手,这里就聊聊四次挥手过程。

1.为什么要挥手

TCP 是有连接的,当建立握手完成后,双方就建立连接,并且双方只能建立一个连接,这是因为对于TCP协议,要成功建立一个新的链接,需要保证新连接四个要素,组合体的唯一性:客户端的IP、客户端的port、服务器端的IP、服务器端的port。也就是说,服务器端的同一个IP和port,可以和同一个客户端的多个不同端口成功建立多个TCP链接(与多个不同的客户端当然也可以),只要保证【Server IP + Server Port + Client IP + Client Port】这个组合唯一不重复即可,但是正常我们使用的客户端都是一个端口建立连接,且是全双工的,任何一个方向都可向对端发送数据。如果在使用完成后不进行挥手,两端会保持连接状态,并且为了保持连接做各种包的检测等,且不能再发起连接,一直占用客户端和服务端的资源,且连接数过多直接导致服务端连接队列爆满,无法再连接新的客户端,且资源消耗严重。挥手是双方的一个约定,双方挥手完成后,对端将不会收到消息,连接资源释放。
那么正常时候当tcp连接建立起来后,就可以在两个方向传输数据流,当tcp 的网络应用进程在没有数据要发送时,就可以发出关闭连接的命令,释放连接,tcp是通过FIN 标识符,置1 的数据段来作为关闭传输连接的命令,从而关闭本端数据流的,但是本端仍然可以继续接收来自对端的数据段,直到对端也使用了同样的方法关闭那个方向的数据流为止,这时整个双方传输连接就彻底关闭了。

2.4次挥手的过程是什么样的?

相对tcp 连接的三次握手过程,tcp 传输链接的释放需要经过四次握手或者说4次挥手。这是由tcp 的半关闭特性造成的,因为tcp连接是全双工的(即数据在两个方向上能同时传递,就像一条双向通行的公路一样,两端车辆都可以通行,再抽象点就是类似于打电话一样,你即可以听到对方的说话,本身也可以说话,对方同样也是这样)每个方向上必须单独关闭,比如说关闭双向公路的一端的一个方向。
TCP 传输连接的关闭的原则是:当一端完成他的数据发送任务后就可以发送一个FIN 字段置 1 数据段来终止那个方向的数据发送,当另一端收到这个FIN 数据段后,必须通知他的应用层“对端已经终止了那个方向的数据传送”,具体有四部组成。
1. 双方都处于ESTABLISHED(连接建立状态) ,如果客户端认为数据全部发送完成,要结束本次传输,则由应用层的对应应用进程调用CLOSE服务原语,然后向服务器发出一个FIN 字段置1 seq=m的数据段,发送后状态为: FIN WAIT 1
2. 服务端收到 FIN=1 seq=m ,向客户端发送 确认消息 ACK=1 seq=n ack=m+1,状态变为:CLOSE WAIT,同时服务器的TCP 实体通知对应的应用进程,释放从客户端到服务器方向的传输连接,进入半关闭状态(半双工),但此时服务器仍可以向客户端发送数据段,客户端也可以接收来自服务端的数据。
3. 当客户端收到服务器的ACK 数据段后,进入到FIN WAIT 2 状态,进一步等待服务器发出连接释放的数据段。
4. 服务端发送完确认消息后,如果有未发送的消息段,等待继续将未发送的数据段发送完成,然后向客户端发送FIN=1 ACK=1,seq=w ack=m+1 ,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w发出连接释放的数据段消息后,状态变为:LAST ACK .
5. 当客户端收到服务端FIN =1 + ACK 释放连接的消息后,向服务端发送一个ACK =1 ack=w+1 seq = m + 1的数据段,状态变为:TIME WAIT 状态,但此时tcp的连接还没有释放,必须等待2MSL (RFC793建议设置MSL 为2分钟) 后,客户端进入到CLOSED状态,彻底释放TCP 连接。
6. 服务端在收到客户端发送的确认关闭数据段后,进入CLOSED 状态,彻底释放连接,此时完成整个tcp 传输连接的释放过程。

这是四次握手详细图解:
四次握手图解
需要注意的是服务端的两次握手消息,中间的一段间隔时间,不光是用来释放了客户端到服务端的连接,还等待将未发送完成的消息发送完成,然后才发送fin断开连接的消息段。

3.不一定都是四次挥手

1.按照上边的逻辑,如果服务端在收到客户端FIN 后在自身条件允许的情况下,其实可以直接发送一个 FIN 和 ACK 包的,就是将第二次和第三次握手合并为一次,这样可以实现三次握手。
2.当客户端和服务端同时发起FIN 情况是什么样?
下面是摘录书上的图:
同时发起关闭
当同时发起关闭连接消息FIN=1 时,A B 同时进入FIN WAIT 1(主动关闭,主机已经发送关闭连接请求,等待对方确认) 状态,当收到对方发来的FIN 消息后都进入 CLOSING(双方同时尝试关闭连接)状态,
向对方发送ACK 确认消息后,双方进入到 TIME WAIT (完成双向连接关闭,等待所有分组消失)状态,等待2ms 后进入到 CLOSED 释放连接。这样的话就是两次握手,每个方向都是两次。

5.为什么最后客户端还要等待 2*MSL的时间呢?

MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。

保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐