当客户端和服务器通过三次握手建立了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连接断开的过程:
- 客户端发起请求,向服务端发送一个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