TIME_WAIT状态原理:

       通信双方建立连接后,主动关闭连接的一方就会进入TIME_WAIT状态。

       客户端主动关闭连接时,会发送最后一个ACK确认,然后就会进入TIME_WAIT状态,再停留2MSL,就会进入CLOSED状态。

       接下来我们看一张图,来说明这一过程:

       TCP/IP中TIME_WAIT状态详解_第1张图片

        上图是TCP“四次挥手”的过程,相信你们都会很了解,下面我们来说说为什么要存在TIME_WAIT状态

        TIME_WAIT状态存在的理由如下:

        (1)可靠地实现TCP全双工连接的终止

                 TCP协议在关闭连接的四次挥手中,最终的ACK是由主动关闭连接的一端(A端)发出的,如果这个ACK丢失,对方(B端)将 重发出最终的FIN,因此A 端必须维护状态信息(TIME_WAIT)允许它重发最终的ACK.如果A端不维持TIME_WAIT状态,而是处于CLOSED状态,那么A端将响应RST报文段,B端收到后,将此报文段解释成一个错误。因而,要实现TCP全双工的正常终止,必须处理终止过程中四个分节任何一个报文段丢失的情况,主动关闭连接的A端必须维持TIME_WAIT状态。

         (2)允许老的报文段在网络中消失

                  TCP报文段可能由于路由器异常而“迷路”,在迷途期间,TCP发送端可能因为确认超时而而重发这个分组,迷路的分组在路由器修复后也会被送到最终目的地,这个迟到的分组到达时就会引起问题,在关闭前一个连接之后,B又收到这个早已失效的连接请求报文段后,就误认为是A又发出一次新的连接请求,于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,只要B发出确认,新的连接就建立了。为了避免这种情况,TCP协议不允许处于TIME_WAIT状态的A端再次建立一个新的连接,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个新TCP连接之后,来自旧连接的重复分组已在网络中消失了。

       TIME_WAIT状态持续时间是2MSL(在我的下一篇博客中会讲解)时间,大概是1~4分钟,windows操作系统就是4分钟。

下面我们来进一步讨论这个问题:

                                                                                                        客户端主动关闭连接

       注意一个问题,进入TIME_WAIT状态的一般情况下是客户端。大多数服务器端一般执行被动关闭,服务器不会进入TIME_WAIT状态。当在服务器端关闭某个服务再重启时,服务器是会进入TIME_WAIT状态的。

举个例子:

       1.客户端连接服务器端的80服务,这时客户端会启用一个本地的端口访问服务器的80,访问完成后关闭此连接,立刻再次访问服务器的80,这时客户端会启用本地的另一个端口,而不是刚才使用的那个本地端口,原因就是刚才的那个连接还处于TIME_WAIT状态。

       2.客户端连接服务器的80服务,这时服务器关闭80端口,立刻再次重启80端口的服务,这时可能不会成功启动,原因也是服务器的连接还处于TIME_WAIT状态。

      服务器提供服务时,一般监听一个端口就够了(例如80端口),客户端则是使用一个本地的空闲端口(大于1024),与服务器的80端口建立连接,当通信使用短连接,并且由客户端主动关闭连接时,主动关闭连接的客户端会产生TIME_WAIT状态的连接,一个TIME_WAIT状态的连接就占用了一个本地端口。这样在TIME_WAIT状态结束之前,本地最多能承受6万多个TIME_WAIT状态的连接,就无端口可用了。客户端与服务器进行短连接的TCP通信,如果在同一台机器上进行压力测试模拟上万的客户请求,并且循环与服务器端进行短连接通信,那么这台机器将产生4000个左右的TIME_WAITsocket,后续的短连接就会产生address already in use:connect的异常。

                                                                                                      服务器端主动关闭连接

       服务器提供服务时,一般监听一个端口就够了(例如80端口),客户端则是使用一个本地的空闲端口(大于1024),与服务器的80端口建立连接,当通信使用短连接,并且由服务端主动关闭连接时,主动关闭连接的服务端会产生TIME_WAIT状态的连接。由于都连接到服务器端80端口,服务器端的TIME_WAIT状态的连接会有很多个,假如server一秒钟处理1000个请求,那么就会积压240秒*1000=24万个TIME_WAIT的记录,服务器有能力维护这24万个记录。

       大多数服务器端一般执行被动关闭,服务器不会进入TIME_WAIT状态,服务端为了解决这个TIME_WAIT问题,可选的方式有3种:

              (1)保证由客户端主动发起关闭

              (2)关闭的时候使用RST方式

              (3)对处于TIME_WAIT状态的TPC允许重用

我们来总结一下:

       通过上面的讨论,我们知道TIME_WAIT状态是友好的,并不是多余的,TCP要保证在所有可能的情况下使得所有的数据都能够正确送达。当你关闭一个scket时,主动关闭一端的socket将进入TIME_WAIT状态,而被动关闭的一方则进入CLOSED状态,这的确能够保证所有的数据都被传送。当一个SOCKET关闭的时候,是通过两端四次挥手完成的,当一端调用close()时,就说明本端没有数据要传送了,这好似看来在握手完成以后,socket就可以处于CLOSED状态了,其实不然,原因是这样安排状态有两个问题,首先我们没有任何机制保证最后的一个ACK能够正常传输,第二,网络仍然可能有残余的数据包,我们也必须能够正常处理。TIME_WAIT状态就是为了解决这两个问题而生的!!!!。