本文转自此博文,因无法联系作者擅自转载,若需要删除请作者留言

只有首先调用close()发起主动关闭的一方才会进入TIME_WAIT状态,进入TIME_WAIT状态的TCP连接需要经过2MSL才能回到初始状态,其中,MSL是指Max Segment Lifetime,即数据包在网络中的最大生存时间。每种TCP协议的实现方法均要指定一个合适的MSL值,如RFC1122给出的建议值为2分钟,又如Berkeley体系的TCP实现通常选择30秒作为MSL值。这意味着TIME_WAIT的典型持续时间为1-4分钟。

产生原因及好处

对于TIME_WAIT的存在,有两个理由。一个原因是为了防止一个连接中延迟的数据段会被后序的连接错误的解析。当一个连接处于2MSL状态的时候,任何到达的数据段都将会被丢弃。第二个原因是为了实现TCP全双工连接的终止可靠性。

为实现TCP这种全双工(full-duplex)连接的可靠释放

参考TCP释放连接4次挥手过程,假设发起active close的一方(通常为client)发送的ACK(4次交互的最后一个包)在网络中丢失,那么由于TCP的重传机制,执行passive close的一方(通常为server)需要重发其FIN,在该FIN到达client(client是active close发起方)之前,client必须维护这条连接的状态(尽管它已调用过close),具体而言,就是这条TCP连接对应的(local_ip, local_port)资源不能被立即释放或重新分配。直到romete peer重发的FIN达到,client也重发ACK后,该TCP连接才能恢复初始的CLOSED状态。如果active close方不进入TIME_WAIT以维护其连接状态,则当passive close方重发的FIN达到时,active close方的TCP传输层会以RST包响应对方,这会被对方认为有错误发生(而事实上,这是正常的关闭连接过程,并非异常)!!!!。

为使旧的数据包在网络因过期而消失

为说明这个问题,我们先假设TCP协议中不存在TIME_WAIT状态的限制,再假设当前有一条TCP连接:(local_ip, local_port, remote_ip,remote_port),因某些原因,我们先关闭,接着很快以相同的四元组建立一条新连接。本文前面介绍过,TCP连接由四元组唯一标识,因此,在我们假设的情况中,TCP协议栈是无法区分前后两条TCP连接的不同的,在它看来,这根本就是同一条连接,中间先释放再建立的过程对其来说是“感知”不到的。这样就可能发生这样的情况:前一条TCP连接由local peer发送的数据到达remote peer后,会被该remot peer的TCP传输层当做当前TCP连接的正常数据接收并向上传递至应用层(而事实上,在我们假设的场景下,这些旧数据到达remote peer前,旧连接已断开且一条由相同四元组构成的新TCP连接已建立,因此,这些旧数据是不应该被向上传递至应用层的),从而引起数据错乱进而导致各种无法预知的诡异现象。作为一种可靠的传输协议,TCP必须在协议层面考虑并避免这种情况的发生,这正是TIME_WAIT状态存在的第2个原因。

具体而言,local peer主动调用close后,此时的TCP连接进入TIME_WAIT状态,处于该状态下的TCP连接不能立即以同样的四元组建立新连接,即发起active close的那方占用的local port在TIME_WAIT期间不能再被重新分配。由于TIME_WAIT状态持续时间为2MSL,这样保证了旧TCP连接双工链路中的旧数据包均因过期(超过MSL)而消失,此后,就可以用相同的四元组建立一条新连接而不会发生前后两次连接数据错乱的情况。

危害

TIME_WAIT表示socket可以进入和留存相当长一段时间的状态,如果系统中有很多 socket 处于TIME_WAIT状态,当需要创建新的 socket 连接的时候可能会受到影响,这也会影响到程序的扩展性!!!。

之所以TIME_WAIT能够影响系统的扩展性是因为在一个TCP连接中,一个Socket如果关闭的话,它将保持TIME_WAIT状态大约 4分钟 。如果很多连接快速的打开和关闭的话,系统中处于TIME_WAIT状态的socket将会积累很多,由于本地端口数量的限制,同一时间只有有限数量的socket连接可以建立,如果太多的socket处于TIME_WAIT状态,你会发现,由于用于新建连接的本地端口太缺乏,将会很难再建立新的对外连接。!!!!!!!!!!!!!!!!!!!

如何避免?

由于本地端口的缺乏,TIME_WAIT的存在影响的是出站连接的建立,这些本地端口由操作系统进行自动的分配,因此,优化的方法是增加本地端口的范围!!!!!!,在Windows下,你可以调整 MaxUserPort 注册表项。注意的是,很多Windows系统下默认的端口范围比较小,大约4000个左右,这对很多客户端服务器系统来说太少了。

其他方法: (1)缩短2MSL的时间 (2)使用SO_REUSEADDR允许连接重用 (3)设计协议避免TIME_WAIT产生的问题

为什么TIME_WAIT需要2MSL

nodekey:
转载的文章中并没有细说,只提到旧的数据包失去寿命,而就一个数据包失去寿命只有一个MSL,2MSL是为了连应答旧数据包的数据包也失去寿命,这样2MSL就能够保证了.