本文主要分析为什么TIME_WAIT状态的持续时间是2MSL而不是1MSL,3MSL或其它的时长,而不会详细描述为什么需要TIME_WAIT状态。
阅读本文需要的预备知识:
正文
其实这个问题在《TCP/IP详解》以及《UNIX网络编程》这两本书中都有提及,但这两本书上的描述都比较简洁并不是特别容易理解,记得在第一次看《UNIX网络编程》时,我曾经反复阅读相关段落并花了不少时间来想这个问题,但并没有搞得很清楚,始终是懂非懂的样子,直至后来有机会参与TCP/IP协议栈的开发后才真正got到这个问题的关键点。
根据第三版《UNIX网络编程 卷1》2.7节,TIME_WAIT状态的主要目的有两个:
很明显,要实现上述两个目标,TIME_WAIT状态需要持续一段时间,但这段时间应该是多长呢?
如果只考虑上述第一个目标,则TIME_WAIT状态需要持续的时间应该参考对端的RTO(重传超时时间)以及MSL(报文在网络中的最大生存时间)来计算而不是仅仅按MSL来计算,因为只要对端没有收到针对FIN报文的ACK,就会一直持续重传FIN报文直到重传超时,所以最能实现完美关闭连接的时长计算方式应该是从对端发送第一个FIN报文开始计时到它最后一次重传FIN报文这段时长加上MSL,但这个计算方式过于保守,只有在所有的ACK报文都丢失的情况下才需要这么长的时间;另外,第一个目标虽然重要,但并不十分关键,因为既然已经到了关闭连接的最后一步,说明在这个TCP连接上的所有用户数据已经完成可靠传输,所以要不要完美的关闭这个连接其实已经不是那么关键了。因此,(我猜)RFC标准的制定者才决定以网络丢包不太严重为前提条件,然后根据第二个目标来计算TIME_WAIT状态应该持续的时长。
再来看一下《UNIX网络编程》在描述为什么需要TIME_WAIT状态时的一段话:
Since the duration of the TIME_WAIT state is twice the MSL, this allows MSL seconds for packet in one direction to be lost, and another MSL seconds for the reply to be lost. By enforcing this rule, we are guaranteed that when we successfully establish a TCP connecton, all old duplicates from previous incarnations of the connection have expired in the network.
这段文字说明了TIME_WAIT状态持续2MSL的时间可以让一个TCP连接的两端发出的报文都从网络中消失,从而保证下一个使用了相同四元组的tcp连接不会被上一个连接的报文所干扰。
如何理解TIME_WAIT状态持续2MSL的时间就可以让一个TCP连接的两端发出的报文都从网络中消失呢?
首先我们需要了解如下要点:
下面我们开始分析为什么在发送了最后一个ACK报文之后需要等待2MSL时长来确保没有任何属于当前连接的报文还存活于网络之中(前提是在这2MSL时间内不再收到对方的FIN报文,但即使收到了对端的FIN报文也并不影响我们的讨论,因为如果收到FIN则会回复ACK并重新计时)。
为了便于描述,我们设想有一个处于拆链过程中的TCP连接,这个连接的两端分别是A和B,其中A是主动关闭连接的一端,因为刚刚向对端发送了针对对端发送过来的FIN报文的ACK,此时正处于TIME_WAIT状态;而B是被动关闭的一端,此时正处于LAST_ACK状态,在收到最后一个ACK之前它会一直重传FIN报文直至超时。随着时间的流逝,A发送给B的ACK报文将会有两种结局:
综上所述,TIME_WAIT至少需要持续2MSL时长,这2个MSL中的第一个MSL是为了等自己发出去的最后一个ACK从网络中消失,而第二MSL是为了等在对端收到ACK之前的一刹那可能重传的FIN报文从网络中消失。另外,虽然说维持TIME_WAIT状态一段时间有2个目的,但这段时间具体应该多长主要是为了达成上述第二个目的而设计的。
最后,如果你觉得本文对你有帮助的话,麻烦帮忙点一下文末右下角的 在看 或转发到朋友圈,非常感谢!