当客户端和服务器通过三次握手建立了 TCP 连接以后,当数据传送完毕,肯定是要断开 TCP 连接的。那对于 TCP 的断开连接,就有了四次挥手(TCP Four-way Wavehand)。
四次挥手(TCP Four-way Wavehand)
由于 TCP 连接是全双工的,因此每个方向的连接必须单独地进行关闭,于是 TCP 连接的断开需要进行 “四次挥手”(两端分别进行 FIN+ACK 和 ACK 两次挥手)。

TCP 连接断开的过程:
- 客户端发起请求,向服务端发送一个 FIN 报文段(其中 Seq = x, Ack = l),用来关闭从客户端到服务端的传输。客户端的状态变为 FIN_WAIT_1 状态。此时客户端仍然可以接收数据。如果这之前发出的数据中存在没有 ACK 的,客户端仍然会重发这些数据。
- 服务端收到客户端的 FIN 包,然后向客户端发回一个 ACK 报文段(Ack = x + 1, Seq = l)作为确认,此后服务端进入 CLOSE_WAIT 状态。
- 同时,服务端向客户端发送一个 FIN 报文段(Seq = l, Ack = x + 1),用来关闭从服务端到客户端的传输,此后服务端的状态变为 LAST_ACK。
- 客户端收到服务端发送的 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