简析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/IP详解--TIME_WAIT状态详解

Socket中的TIME_WAIT状态 在高并发短连接的server端,当server处理完client的请求后立刻closesocket此时会出现time_wait状态然后如果client再并发...
  • yusiguyuan
  • yusiguyuan
  • 2014年03月18日 10:29
  • 5637

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

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

服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

近来在写服务端的时候纠结服务端要不要主动调用close()关闭socket,后来深入了解tcp断开连接四次握手,心中有点答案了。 下面内容均为转载:昨天解决了一个HttpClient调用错误导致的服...
  • luomoshusheng
  • luomoshusheng
  • 2016年07月25日 23:44
  • 2694

通讯系统经验谈【一】TCP连接状态分析:SYNC_RECV,CLOSE_WAIT,TIME_WAIT

摘自:http://maoyidao.iteye.com/blog/1744277 面试时看到应聘者简历中写精通网络,TCP编程,我常问一个问题,TCP建立连接需要几次握手?95%以上的...
  • chinaclock
  • chinaclock
  • 2016年01月11日 20:59
  • 965

服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

转自http://blog.csdn.net/shootyou/article/details/6622226,展开了链接
  • Kiritow
  • Kiritow
  • 2016年03月14日 22:59
  • 1411

socket链接的关闭close和shutdown的区别_TIME_WAIT和CLOSE_WAIT什么时刻出现_如何处理

TCP主动关闭连接 appl: close(), --> FIN FIN_WAIT_1 //主动关闭socket方,调用close关闭socket,发FIN ...
  • liuhongxiangm
  • liuhongxiangm
  • 2013年09月15日 08:41
  • 2071

TCP/IP详解--TIME_WAIT状态存在的原因

1. 实际问题         初步查看发现,无法对外新建TCP连接时,线上服务器存在大量处于TIME_WAIT状态的TCP连接(最多的一次为单机10w+,其中引起报警的那个模块产生的TIME_WAI...
  • yusiguyuan
  • yusiguyuan
  • 2014年09月01日 20:15
  • 3317

一个解除TCP连接的TIME_WAIT状态限制的简便方法

/************************************ *              版权声明 *   本文为本人原创,本人拥有此文的版权。鉴于本人持续受益于开源软件社区, ...
  • wyhang0
  • wyhang0
  • 2014年10月26日 22:36
  • 1626

应用环境下的TIME_WAIT和CLOSE_WAIT处理

昨天解决了一个HttpClient调用错误导致的服务器异常,具体过程如下: http://blog.csdn.net/shootyou/article/details/6615051 里头的分析过程有...
  • bytxl
  • bytxl
  • 2015年06月10日 08:34
  • 642

为什么TCP的TIME_WAIT状态要保持2MSL?

TIMEWAIT状态也称为2MSL等待状态。 每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime)。 它是任何报文段被丢弃前在网络内的最长时间。 ...
  • unix21
  • unix21
  • 2013年11月24日 13:14
  • 3973
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:简析TCP协议的TIME_WAIT与CLOSE_WAIT状态
举报原因:
原因补充:

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