前言
某机器上残留了很多CLOSE_WAIT状态的TCP连接,使用netstat却看不到是哪一个进程在使用。
分析
TCP状态机
回顾一下TCP的状态机,处于ESTABLISHED状态的TCP连接收到FIN信号后,回复ACK,会进入到CLOSE_WAIT状态。
通常的CLOSE_WAIT状态的TCP连接
通常情况下,我们可以通过netstat -aptn来获取到TCP连接的信息,如上图,可以知道CLOSE_WAIT状态的TCP连接属于50871进程,大概率是用户逻辑处理有问题,没有执行close/shutdown来关闭TCP连接。
没有进程号的CLOSE_WAIT状态的TCP连接
还有一种情况,没有进程归属的CLOSE_WAIT状态的TCP连接。
同时,我们使用lsof命令,或者ls -al /proc/PID/fd同样也看不到目标进程有对应的fd。
那么,这些连接是怎么来的呢?
在TCP的三次握手之后,TCP连接已经进入了ESTABLISHED。而且,不管server端是否执行accept,都会完成三次握手。
在三次握手完成之后(内核态完成),在用户进程没有执行accept之前,内核会把对应的socket加入到listen的队列中。在队列中的socket,在server端执行accept之前,client执行了close/shutdown操作,在server端就会看到上图中的现象:大量的没有进程归属的CLOSE_WAIT状态的TCP连接。
解决办法
只要server及时执行accept操作即可。否则,因为listen的队列已经满了,无法让其他的连接正常执行。
那么,能不能自动丢弃这种没有进程归属的CLOSE_WAIT状态的TCP连接?作者查询linux-4.19的TCP逻辑,发现只有两种情况下会有从listen的队列中的dequeue操作:1,执行accept操作; 2,关闭listen fd。