图片来源自网络
“挥手”是为了终止连接,TCP四次挥手的流程图如下:
- 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态;
- 客户端发送报文,完成信号FIN=1,序号seq=u
- 进入完成FIN_WAIT_1状态,等待服务端确认
- 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态
- 服务端发送确认报文,确认信号ACK=1,序号=v,确认序号ack=u+1
- 此时服务端就进入Close-wait状态,半关闭状态
- 此时客户端就进入FIN-wait状态,终止等待状态,等待服务器发送释放连接报文
- 这里有可能服务端还会持续完成数据传送。因此seq值会改变
- 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
- 服务端发送数据完成报文,完成信号FIN=1,确认信号ACK=1,序号seq=w,确认信号ack=u+1
- 此时服务端进入最后确认状态,等待客户端发送确认
- 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
- 客户端确认报文,确认信号ACK=1,序号seq = u+1,确认序号ack=w+1
- 此时服务端进入关闭状态
- 此时客户端进入TIME-WAIT状态,时间等待状态,还未释放连接,必须经过2*MSL的时间才会进行释放。RFC定义为两分钟,而Linux的时间为30秒
- 为什么会有TIME_WAIT状态
- 确保有足够时间让对方(上图为server端)收到ACK包
- 避免新旧连接混绕
- 为什么需要四次握手才能断开连接
- 因为全双工,发送方和接收方都需要FIN报文和ACK报文
- 服务器出现大量CLOSE_WAIT状态的原因
- 对方关闭socker连接,我方忙于读或写,没有及时关闭连接
- 检查代码,特别是释放资源的代码
- 检查配置,特别是处理请求的线程配置