问题的判断
用 netstat -an
命令可以查看网络连接的状态。
用 netstat -an | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
命令可以查看各种状态连接的数量。
问题产生的原因
TCP结束时的4次挥手:
-
客户端(当前场景意义上的,与应用程序的角色无关)需要关闭TCP连接,首先发送FIN到服务端,发送后客户端进入FIN-WAIT-1状态等待ACK
-
服务端接收到FIN,返回ACK进入CLOSE_WAIT状态,等待应用程序进行一些收尾工作
-
客户端收到ACK后进入FIN-WAIT-2状态,等待接收服务端之后发送的FIN
-
进入CLOSE_WAIT状态的服务端待应用程序完成收尾工作后,发送FIN到客户端,然后进入LAST-ACK状态等待ACK
-
客户端收到服务端发送的FIN后返回ACK,并进TIME-WAIT状态,等2个MSL(Maximum Segment Life)后CLOSED
-
服务端收到返回的ACK后CLOSED
Linux有一个 tcp_fin_timeout
设置,控制了FIN_WAIT2的最大生命周期,而CLOSE_WAIT没有,所以如果这一个过程出现异常,客户端TCP连接会关闭,而服务端连接一直处在CLOSE_WAIT状态。
造成大量CLOSE_WAIT的可能原因(来自于参考资料):
-
服务端程序没有正确关闭连接
-
服务端收尾工作太慢,客户端没等到FIN就已经超时了
-
客户端设置的超时时间太短