相信很多人都遇到过这个问题,一旦发现网络变慢了。我们常常要做的第一件事情就是:

netstat -a | grep TIME_WAIT | wc -l 

妈呀,几千个TIME_WAIT。

什么是TIME-WAIT呢? 大家知道,由于socket是全双工的工作模式,一个socket的关闭,是需要四次握手来完成的,如下图所示:

TCPDisconnectState.png

(1)主动关闭连接的一方,调用close操作,协议层发送FIN包

(2)被动关闭的一方收到FIN包后,协议层回复ACK,然后,被动关闭的一方,进入CLOSE_WAIT状态。主动关闭的一方等待对方关闭,则进入FIN_WAIT_2状态;此时,主动关闭的一方 等待 被动关闭一方的应用程序,调用close操作

(3)被动关闭的一方在完成所有数据发送后,调用close操作。此时,协议层发送FIN包给主动关闭的一方,等待对方的ACK,被动关闭的一方进入LAST_ACK状态;

(4)主动关闭的一方收到FIN包,协议层回复ACK;此时,主动关闭连接的一方,进入TIME_WAIT状态。而被动关闭的一方,进入CLOSED状态。

(5)等待2MSL时间,主动关闭的一方,结束TIME_WAIT,进入CLOSED状态

通过上面的一次socket关闭操作,我们可以得出以下几点:

(1)主动关闭连接的一方,也就是主动调用socket的close操作的一方,最终会进入TIME_WAIT状态

(2)被动关闭连接的一方,有一个中间状态,即CLOSE_WAIT,因为协议层在等待上层的应用程序,主动调用close操作后才主动关闭这条连接

(3)TIME_WAIT会默认等待2MSL时间后,才最终进入CLOSED状态。

(4)在一个连接没有进入CLOSED状态之前,这个连接是不能被重用的!

所以,TIME_WAIT并不可怕,CLOSE_WAIT才可怕,因为CLOSE_WAIT很多,表示说要么是你的应用程序写的有问题,没有合适的关闭socket;要么是说,你的服务器CPU处理不过来(CPU太忙)或者你的应用程序一直睡眠到其它地方(锁,或者文件I/O等等),你的应用程序获得不到合适的调度时间,造成你的程序没法真正的执行close操作。