简析TCP协议的TIME_WAIT与CLOSE_WAIT状态

原创 2015年07月11日 09:36:09

一、服务器异常

如果服务器出了异常,十之八九都是以下两种情况:

1.服务器保持了大量TIME_WAIT状态

2.服务器保持了大量CLOSE_WAIT状态

二、TIME_WAIT状态

1、TIME_WAIT状态存在的两个理由:

1)让4次握手关闭流程更加可靠;4次握手的最后一个ACK是是由主动关闭方发送出去的,若这个ACK丢失,被动关闭方会再次发一个FIN过来。若主动关闭方能够保持一个2MSL的TIME_WAIT状态,则有更大的机会让丢失的ACK被再次发送出去。

如果主动关闭端不维持TIME_WAIT状态,而是处于CLOSED 状态,那么当主动端ACK丢失,被动方将重发最终的FIN,而主动端将响应RST,被动端收到后将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。

因而,要实现TCP全双工连接的正常终止,必须处理终止过程中四个分节任何一个分节的丢失情况,主动关闭连接的A端必须维持TIME_WAIT状态 。

2)允许老的重复分节在网络中消逝,防止lost duplicate对后续新建正常链接的传输造成破坏。lost duplicate在实际的网络中非常常见,经常是由于路由器产生故障,路径无法收敛,导致一个packet在路由器A,B,C之间做类似死循环的跳转。IP头部有个TTL,限制了一个包在网络中的最大跳数,因此这个包有两种命运,要么最后TTL变为0,在网络中消失;要么TTL在变为0之前路由器路径收敛,它凭借剩余的TTL跳数终于到达目的地。但非常可惜的是TCP通过超时重传机制在早些时候发送了一个跟它一模一样的包,并先于它达到了目的地,因此它的命运也就注定被TCP协议栈抛弃。

另外一个概念叫做incarnation connection,指跟上次的socket pair一模一样的新连接,叫做incarnation of previous connection。lost duplicate加上incarnation connection,则会对我们的传输造成致命的错误。

大家都知道TCP是流式的,所有包到达的顺序是不一致的,依靠序列号由TCP协议栈做顺序的拼接;假设一个incarnation connection这时收到的seq=1000, 来了一个lost duplicate为seq=1000, len=1000, 则tcp认为这个lost duplicate合法,并存放入了receive buffer,导致传输出现错误。通过一个2MSL TIME_WAIT状态,确保所有的lost duplicate都会消失掉,避免对新连接造成错误。

2、该状态为什么设计在主动关闭这一方:

(1)发最后ack的是主动关闭一方

(2)只要有一方保持TIME_WAIT状态,就能起到避免incarnation connection在2MSL内的重新建立,不需要两方都有。

3、如何正确对待2MSL TIME_WAIT

RFC要求socket pair在处于TIME_WAIT时,不能再起一个incarnation connection。但绝大部分TCP实现,强加了更为严格的限制。在2MSL等待期间,socket中使用的本地端口在默认情况下不能再被使用。若A 10.234.5.5:1234和B 10.55.55.60:6666建立了连接,A主动关闭,那么在A端只要port为1234,无论对方的port和ip是什么,都不允许再起服务。显而易见这是比RFC更为严格的限制,RFC仅仅是要求socket pair不一致,而实现当中只要这个port处于TIME_WAIT,就不允许起连接。

这个限制对主动打开方来说是无所谓的,因为一般用的是临时端口;但对于被动打开方,一般是server,那就悲剧了,因为server一般是熟知端口。比如http一般端口是80,不可能允许这个服务在2MSL内不能起来。解决方案是给服务器的socket设置SO_REUSEADDR选项,这样的话就算熟知端口处于TIME_WAIT状态,在这个端口上依旧可以将服务启动。当然,虽然有了SO_REUSEADDR选项,但sockt pair这个限制依旧存在。比如上面的例子,A通过SO_REUSEADDR选项依旧在1234端口上起了监听,但这时我们若是从B通过6666端口去连它,TCP协议会告诉我们连接失败,原因为Address already in use。


三、CLOSE_WAIT状态

因为linux分配给一个用户的文件句柄是有限的,而TIME_WAIT和CLOSE_WAIT两种状态如果一直被保持,那么意味着对应数目的通道就一直被占着,一旦达到句柄数上限,新的请求就无法被处理了,接着应用程序可能返回大量Too Many Open Files异常。

1、Close_Wait引发的问题

Close_Wait会占用一个连接,网络可用连接小。数量过多,可能会引起网络性能下降,并占用系统非换页内存。 尤其是在有连接池的情况下(比如HttpRequest)

会耗尽连接池的网络连接数,导致无法建立网络连接。

2、解决方法

下面来讨论下这两种情况的处理方法,优化系统内核参数解决TIME_WAIT可能很容易,可以通过修改/etc/sysctl.conf文件解决;

但是应对CLOSE_WAIT的情况还是需要从程序本身出发。因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的。从上面的图可以看出来,如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出FIN信号,一般原因都是TCP连接没有调用关闭方法。换句话说,就是在对方连接关闭之后,程序里没有检测到,比如对方异常关闭(不采用close,如断电),或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直被程序占着。这种情况,通过服务器内核参数也没办法解决,服务器对于程序抢占的资源没有主动回收的权利,除非终止程序运行,一定程度上,可以使用TCP的KeepAlive(心跳包)功能,如果在某个时间段内不去确认,就说名该连接的一方已经关闭,让操作系统替我们自动清理掉CLOSE_WAIT连接。


相关文章推荐

TCP协议的TIME_WAIT状态详解

原创文章,转载请注明出处:www.ganquan.org 我发现有个公司面试的时候问了对TCP协议比较细节的地方,那就写一下帮助自己加深理解和记忆。在开始说TIME_WAIT状态之前,要知道TC...

TCP协议--TIME_WAIT状态

2MSL TIME_WAIT状态存在的理由:TIME_WAIT状态的存在有两个理由:(1)让4次握手关闭流程更加可靠;4次握手的最后一个ACK是是由主动关闭方发送出去的,若这个ACK丢失,被动关闭方会...

TCP协议之TIME_WAIT状态

上次面试linux软件开发工程师,以为自己比较了解TCPIP,没想到被问到TCP协议中TIME_WAIT状态的时候,却不能回答,下面总结一下整个过程:         其实面试官问得还是挺细的,TC...

回顾一下TCP/IP连建立断开,以及常见大量的TIME_WAIT和CLOSE_WAIT状态原因

连接建立和断开过程:   CLOSED: 表示初始状态。 LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。 SYN_RC...

Linux网络tcp连接大量CLOSE_WAIT和TIME_WAIT状态的出现和解决方法

关于CLOSE_WAIT和TIME_WAIT状态,服务器端都有可能出现,TIME_WAIT出现应该是短连接较多,需要通过修改内核参数解决,CLOSE_WAIT状态则是服务器程序可能有问题,服务器需要主...

TCP/IP 协议 TCP TIME_WAIT状态(2MSL)

转载自:http://blog.chinaunix.net/u1/40133/showart_1764444.html 连接进程是通过一系列状态表示的,这些状态有:LISTEN,SYN-SENT...
  • zqt520
  • zqt520
  • 2012年04月14日 00:47
  • 351

TCP连接中的TIME_WAIT状态

1 TCP关闭时的四次握手Tcp连接在关闭的的时候,执行的是一个四次握手的过程,下图是客户端发起的关闭时客户端和服务器的状态转换图具体过程如下:1、 客户端发送FIN报文段,进入FIN_WAIT_1状...

TCP TIME_WAIT状态

转自:http://www.cnblogs.com/jason-jiang/archive/2006/11/03/549337.html TCP TIME_WAIT状态 关键词: TIME_W...

TCP/IP TIME_WAIT状态原理

TIME_WAIT状态原理 ---------------------------- 通信双方建立TCP连接后,主动关闭连接的一方就会进入TIME_WAIT状态。 客户端主动关闭连接...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:简析TCP协议的TIME_WAIT与CLOSE_WAIT状态
举报原因:
原因补充:

(最多只允许输入30个字)