【Network】TCP 四次挥手(TCP Four-way Wavehand)

Posted by 西维蜀黍 on 2019-05-06, Last Modified on 2021-09-21

当客户端和服务器通过三次握手建立了TCP连接以后,当数据传送完毕,肯定是要断开TCP连接的。那对于TCP的断开连接,就有了四次挥手(TCP Four-way Wavehand)。

四次挥手(TCP Four-way Wavehand)

由于TCP连接是全双工的,因此每个方向的连接必须单独地进行关闭,于是TCP连接的断开需要进行“四次挥手”(两端分别进行FIN+ACK和ACK两次挥手)。

![TCP 四次握手 - TCP Four-way Handshake](assets/TCP 四次握手 - TCP Four-way Handshake.png)

TCP连接断开的过程:

  1. 客户端发起请求,向服务端发送一个FIN报文段(其中Seq = x, Ack = l),用来关闭从客户端到服务端的传输。客户端的状态变为FIN_WAIT_1状态。此时客户端仍然可以接收数据。如果这之前发出的数据中存在没有ACK的,客户端仍然会重发这些数据。
  2. 服务端收到客户端的FIN包,然后向客户端发回一个ACK报文段(Ack = x + 1, Seq = l)作为确认,此后服务端进入CLOSE_WAIT状态。
  3. 同时,服务端向客户端发送一个FIN报文段(Seq = l, Ack = x + 1),用来关闭从服务端到客户端的传输,此后服务端的状态变为LAST_ACK
  4. 客户端收到服务端发送的FIN报文段后,进入TIME_WAIT状态,然后向服务端发回一个ACK包(Ack = l + 1, Seq = x + 1)作为确认。服务端收到后,Server进入CLOSED状态。最终四次挥手结束,连接断开(CLOSE)。

注意:TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSED状态,原因:

  • TIME_WAIT确保有足够的时间让对端收到了ACK(如果被动关闭的那方没有收到ACK,就会触发被动端重发FIN,一来一去正好2个MSL)
  • 有足够的时间让这个连接不会跟后面的连接混在一起(部分路由器会缓存数据包导致连接重用)

以下为动画演示四次挥手的交互过程:

四次握手时的状态变化

为什么要四次挥手

TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着:

  • 当主机1向主机2发出FIN报文段时,只是表示主机1已经没有数据要发送了,即主机1告诉主机2,它的数据已经全部发送完毕了;
  • 但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2仍然还是可以发送数据到主机1的;
  • 当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

Wireshake抓包学习TCP 四次挥手

可以增加tcp && tcp.flags.fin == 1过滤条件,可以让我们找到两条FIN报文段。去掉过滤条件,并找到这两条FIN报文段对应的ACK报文段。

一个完整的四次挥手过程如下所示:

分析

#6939

Client -> Server

[FIN, ACK]

Sequence number 196

Acknowledgement number: 1689

#6941

Server -> Client

[ACK]

Sequence number 1689

Acknowledgement number: 197

#6942

Server -> Client

[FIN, ACK]

Sequence number 1689

Acknowledgement number: 197

#6951

Client -> Server

[ACK]

Sequence number 197

Acknowledgement number: 1690

Reference