首先,关于报文的格式可以看上篇。
刚开始双方都处于establised状态,我们假设客户端先发起请求。
1.第一次挥手,客户端发送一个FIN报文,报文中指定一个序列号seq。此时客户端处于FIN_WAIT1状态。
2.第二次挥手,服务端收到FIN之后,会发送ACK(客户端的seq值+1)确认报文,表明已收到客户端的报文了,此时服务端处于CLOSE_WATI状态。
3.第三次挥手,如果服务端也准备好断开连接,也发FIN报文并指定一个序列号,此时服务端处于LAST_ACK状态。
4.第四次挥手,客户端发送ACK报文作为应答(服务端的seq+1),此时客户端处于TIME_WAIT状态,需要等待确保服务端收到自己的ACK报文后才会进入CLOSED状态。(如果没有收到,服务端会重新发FIN报文,客户端收到之后就知道之前的ACK报文丢失了,然后再次发送ACK报文。)
5.服务端收到ACK报文后,就关闭连接了,处于CLOSED状态。
TIME_WAIT的持续时间一般时一个报文的来回时间。一般会设置一个计时,如果过了这个时间没有收到服务端的FIN报文,就代表服务端成功接收了ACK报文,此时处于CLOSED状态。
大量time_wait阶段出现的场景及造成的影响:
在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。
解决办法:
优化内核参数,让服务器能够快速回收和重用那些TIME_WAIT的资源。
net.ipv4.tcp_tw_reuse = 1 %表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 %表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout %修改系默认的 TIMEOUT 时间