什么是TCP四次分手?
服务端和客户端建立TCP连接时需要三次握手,而断开时,服务端和客户端一共需要发送4次数据包才能真正完成一次TCP连接的断开。
四次分手的过程
1、某个应用进程首先调用close,我们称为这一端执行主动关闭(active close)。这一端的TCP于是发送一个FIN分节,表示数据发送完毕。
2、接收到FIN的另一端执行被动关闭,这个FIN由TCP确认,它的接收也作为文件结束符传递给接收方应用进程(放在已排队等候该应用进程接收的任何其他数据之后),因为FIN的接收意味着应用进程在相应连接上再也接收不到额外数据。
3、一段时间后,接收到文件结束符的应用进程将调用close关闭它的套接口,这导致它的TCP也发送一个FIN。
4、接收到这个FIN的原发送方TCP(即执行主动关闭的那一端)对它进行确认。
FIN占据1个字节的序列号空间,与三次握手时的SYN相同,所以每个FIN的ACK确认号是这个FIN的序列号加1.
四次分手数据图解
服务端和客户端完整过程状态
四次分手状态
1、主动关闭方发送FIN,此时主动关闭方状态为:FIN_WAIT_1
2、被动关闭方收到后,回复ack,此时被动关闭方状态为:CLOSE_WAIT
3、主动关闭方收到ack后,状态为FIN_WAIT_2
4、被动关闭方发送FIN,此时状态为LAST_ACK
5、主动关闭方收到后,回复ack,此时状态为TIME_WAIT
6、被动关闭方收到ack后,状态为CLOSED
案例演示
使用nc启动一个服务端,端口为9999,状态为LISTEN
使用telnet连接,模拟一个客户端请求。
完成三次握手
服务端进入ESTABLISHED
数据交互正常
服务端主动关闭连接之后,服务端进入TIME_WAIT状态。
四次分手信息,F表示FIN,小数点表示ack
15:48:26.190236 IP 192.168.70.114.9999 > 192.168.70.170.49707: Flags [F.], seq 185689471, ack 2683462099, win 229, length 0
15:48:26.190568 IP 192.168.70.170.49707 > 192.168.70.114.9999: Flags [.], ack 185689472, win 4106, length 0
15:48:26.190756 IP 192.168.70.170.49707 > 192.168.70.114.9999: Flags [F.], seq 2683462099, ack 185689472, win 4106, length 0
15:48:26.190761 IP 192.168.70.114.9999 > 192.168.70.170.49707: Flags [.], ack 2683462100, win 229, length 0
TIME_WAIT状态
关于TIME_WAIT状态也是面试中的高频题,这种状态是出现在主动关闭方收到被动关闭方发出FIN后,并且主动关闭方也回复了ack时的状态。这个状态的持续时间是最长分节生命期MSL(maximum segment lefetime)的两倍,所以又称2MSL。每个TCP实现都必须选择一个MSL值,这个值建议是2分钟,而传统上使用的是30秒,所以TIME_WAIT状态的延迟在1分钟至4分钟之间。MSL是IP数据包能在互联网中生存的最长时间。
TIME_WAIT状态存在的两个理由
1、实现终止TCP全双工连接的可靠性
2、允许老的重复分节在网络中消失
第一个理由的解释:
为了方便解释,假设服务端为主动关闭方
假设四次分手中,最后一次服务端向客户端发送的ack数据包丢失,那么服务端将重发最终的FIN,所以服务端就必须维护一个状态用来允许可能产生的ack重发。如果不维护,那重发时就会发生RST错误,所以为了保证TCP的可靠性,就必须正确处理连接终止序列四次分手中任何一次数据丢失的请求。
第二个理由的解释:
假设现在有一个192.168.70.114 9999和192.168.70.170 49707的TCP连接,当服务端关闭这个连接后,接着又重新建立起一个相同的IP、端口的连接,此时后一个连接称为前一个连接的化身,因为它们的IP地址和端口号都相同,TCP必须防止来自某个连接的老重复分组在连接终止后又再现,从而被误解成属于同一连接的化身,要实现这种功能,TCP不能给处于TIME_WAIT状态的连接启动新的化身,既然TIME_WAIT状态的持续时间是2MLS,这就足够让某个方向上的分组最多存活MSL秒即被丢弃,另一个方向上的应答最多存活MSL秒也被丢弃(指的就是服务端和客户端),通过这个规则,就能保证当成功建立以个TCP连接时,来自该连接先前化身的老重复分组都已在网络中消失。