
架构之美 2018-03-29 07:54:08
上一篇文章介绍了,三次握手建立连接后,双方就可以进行数据的发送和接收了。假如之后客户端发起了断开连接的请求,那么正常情况下的过程如下图所示:
1.客户端向服务器发送FIN数据包,告知服务端需要断开连接,之后就会FIN_WAIT_1状态。
2.服务端收到FIN数据包后,会向客户端发送Ack包,并继续处理未处理完的数据,然后进入CLOSE_WAIT状态。
3.客户端收到Ack包后进入FIN_WAIT_2状态。
4.服务端数据处理完毕后向客户端发送FIN包,告知自己可以准备断开连接了,然后进入LAST_ACK状态。
5.客户端收到来自服务端的FIN包后,发出ACK确认包,然后进入TIME_WAIT状态。
6.服务端收到客户端的ACK确认包后,关闭socket套接字,进入CLOSED状态。
到这里,正常的流程就走完了,但是也许你要问,客户端还没有CLOSED掉,这是为什么呢?
MSL:即报文最大生存时间,超过这个时间的报文都会被丢弃掉。
TIME_WAIT:客户端发送完ACK包后可能因为网络存在问题导致无法及时到达服务端,那么一定时间后服务端会启动重发机制再次发送FIN包,如果客户端早早就关闭了连接,那么服务端将不再有可能收到Ack确认包。TIME_WAIT的时长就是2倍MSL,想一下为什么是2MSL?
有句话叫“理想很丰满,现实很骨感”,这句话同样适合于计算机的世界,异常总是无处不在。例如突发的网线故障,一方机器奔溃、断电,SYN攻击等情况,倘若连接得不到及时释放,就会造成资源的浪费,甚至影响正常的功能。
解决办法:
1.很多防火墙等对于空闲socket自动关闭;
2.打开TCP协议自带Keep-alive功能,相关参数如下图:
为什么是四次挥手?
客户端发送FIN并不意味着TCP连接立即关闭,因为服务端数据可能还没有发送完毕,为了保证可以继续发送数据,服务端的FIN包并不会立即发给客户端,所以就多出一次报文发送。