本文主要分析为什么 TIME_WAIT 状态的持续时间是 2MSL 而不是 1MSL,3MSL 或其它的时长,而不会详细描述为什么需要 TIME_WAIT 状态。阅读本文需要的预备知识:
其实这个问题在《TCP/IP详解》以及《UNIX网络编程》这两本书中都有提及,但这两本书上的描述都比较简洁并不是特别容易理解,记得在第一次看《UNIX网络编程》时,我曾经反复阅读相关段落并花了不少时间来想这个问题,但并没有搞得很清楚,始终是懂非懂的样子,直至后来有机会参与 TCP/IP 协议栈的开发后才真正 get 到这个问题的关键点。
根据第三版《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连 接的两端发出的报文都从网络中消失呢?
首先我们需要了解如下要点:
rfc793
以及 Linux Kernel 源代码tcp_timewait_state_process
函数)。下面我们开始分析为什么在发送了最后一个 ACK 报文之后需要等待 2MSL 时长来确保没有任何属于当前连接的报文还存活于网络之中(前提是在这 2MSL 时间内不再收到对方的 FIN 报文,但即使收到了对端的 FIN 报文也并不影响我们的讨论,因为如果收到 FIN 则会回复 ACK 并重新计时)。
为了便于描述,我们设想有一个处于拆链过程中的 TCP 连接,这个连接的两端分别是 A 和 B,其中 A 是主动关闭连接的一端,因为刚刚向对端发送了针对对端发送过来的 FIN 报文的 ACK,此时正处于 TIME_WAIT 状态;而 B 是被动关闭的一端,此时正处于 LAST_ACK 状态,在收到最后一个 ACK 之前它会一直重传 FIN 报文直至超时。随着时间的流逝,A 发送给 B 的 ACK 报文将会有两种结局:
t
之后 B 才收到该 ACK,则有0 < t <= MSL
。因为 A 并不知道它发送出去的 ACK 要多久对方才能收到,所以 A 至少要维持 MSL 时长的 TIME_WAIT 状态才能保证它的 ACK 从网络中消失。同时处于 LAST_ACK 状态的 B 因为收到了 ACK,所以它直接就进入了 CLOSED 状态,而不会向网络发送任何报文。所以晃眼一看,A 只需要等待 1 个 MSL 就够了,但仔细想一下其实 1 个 MSL 是不行的,因为在 B 收到 ACK 前的一刹那,B 可能因为没收到 ACK 而重传了一个 FIN 报文,这个 FIN 报文要从网络中消失最多还需要一个 MSL 时长,所以 A 还需要多等一个 MSL。综上所述,TIME_WAIT 至少需要持续 2MSL 时长,这 2 个 MSL 中的第一个 MSL 是为了等自己发出去的最后一个 ACK 从网络中消失,而第二 MSL 是为了等在对端收到 ACK 之前的一刹那可能重传的 FIN 报文从网络中消失。另外,虽然说维持 TIME_WAIT 状态一段时间有 2 个目的,但这段时间具体应该多长主要是为了达成上述第二个目的而设计的。