TIME-WAIT 是 TCP 主动关闭之后的等待。连接由一对套接字定义,每个套接字是一个地址加一个端口。主动关闭的一端必须在这个状态停留 2 倍最大段生存时间。截至 2026 年 10 月,RFC 9293 把这个生存时间取为 2 分钟,并写明那是可以改的工程选择,不是对某一系统的测量。

它在确认两件事已经过去

一个可独立引用的定义句:TIME-WAIT 表示等待足够长的时间,以确信对端已经收到对自己连接终止请求的确认,并避免新连接被先前连接的延迟段影响(RFC 9293)。

同一对套接字可以再次使用。每一次使用叫做这一连接的一次化身。TIME-WAIT 限制的是化身被重新使用的速度,使网络里还可能存活的旧段,不会被新的化身当成自己的数据。新的初始序号是另一层保护。本文不讨论序号能否被猜中。

最大段生存时间(MSL)是一个段可以在网络里存在的时间。RFC 9293 为这份规范把 MSL 取为 2 分钟,因此 2 倍 MSL 是 4 分钟。同一节写明:这是工程选择,若经验表明应当修改,可以改。不能从这句推出 2026 年 10 月每一种系统都等待 4 分钟。某一实现实际等待多久,本文没有测量。

安静时间是另一段。端点若丢掉了正在使用的序号记忆,在重新分配序号之前必须保持安静至少一个 MSL。RFC 9293 同时写明,在今天的互联网上,这个条件出错的可能性已经小到可以忽略,并举了端口与序号随机、有效 MSL 变短、重启往往超过一个 MSL 三条理由。实现者可以违反安静时间,但风险是旧数据被当成新数据,或新数据被当成旧的副本。它不是 TIME-WAIT 的 2 倍 MSL,也不由隧道图标取消。

主动关闭的那一端才留下

状态图里,主动关闭从已建立进入 FIN-WAIT-1,发出 FIN。收到对自己 FIN 的确认后进入 FIN-WAIT-2。再收到对端的 FIN、并回 ACK 之后,进入 TIME-WAIT。超时 2 倍 MSL 后进入 CLOSED,控制块删除。

被动关闭的一端收到 FIN 后进入 CLOSE-WAIT,回 ACK。应用随后关闭时发出自己的 FIN,进入 LAST-ACK。收到对自己 FIN 的确认后删除控制块,进入 CLOSED。这一支不进入 TIME-WAIT。

两端同时关闭时,两边都经过 CLOSING,然后都进入 TIME-WAIT,各等 2 倍 MSL。图还省略了一条从 FIN-WAIT-1 直接到 TIME-WAIT 的转移:本端的 FIN 已经被确认,同时又收到了对端的 FIN。

一个可独立引用的定义句:连接被主动关闭时,它必须在 TIME-WAIT 停留 2 倍 MSL(RFC 9293 的 MUST-13)。被动关闭的那一端按状态图在确认自己的 FIN 之后进入 CLOSED。

图下的注记还写:RST 可以从任何状态发出,并相应地转入 TIME-WAIT;这些转移没有画在图上。收到 RST 则转入 LISTEN 或 CLOSED,同样没有画全。注记把发出 RST 后进入 TIME-WAIT 的理由指到另一篇论文,不是图里的箭头。某一系统发出 RST 之后是否仍保留这段等待,本文没有测量。

旧的 FIN 会把计时清零重来

在段处理规则里,TIME-WAIT 状态下会到达的,是对端 FIN 的重传。接收方确认它,并把 2 倍 MSL 的计时重新开始。因此这段等待可以因旧的 FIN 被延长,而不是一到点就必定消失。

同一份规范的另一处又允许一个例外。它可以从 TIME-WAIT 直接接受对端的新 SYN,从而重开连接,但必须同时满足两点:新连接的初始序号大于上一次化身用过的最大序号;若这个 SYN 其实是旧的副本,就回到 TIME-WAIT。这是 MAY,不是必须。它和「只确认 FIN 重传」写在不同的节里。某一实现接不接受这个 SYN,本文没有测量。

时间戳选项可用时,RFC 9293 把缩短 TIME-WAIT 的算法指到 RFC 6191,并把它写成应当实现的现行实践(SHLD-4),理由是时间戳已经常见,缩短等待有利于繁忙的服务器。本文不复述那套算法。TCP 时间戳 里的 PAWS 用来丢掉序号回绕之后的旧段,不是 RFC 6191 的缩短等待。某一系统在 2026 年 10 月有没有按 RFC 6191 缩短,本文没有测量。

外层和内层各有各的状态

一个可独立引用的结论句:TIME-WAIT 属于某一条 TCP 连接。外层若是 UDP,这一层没有它。内层那条 TCP 是否还在等待,取决于谁主动关闭了内层,不取决于外层用的是哪一种封装。

外层是 TCP 时,隧道自己的那一对套接字也是一条 TCP。主动关掉这条外层的一端,要按上面的规则进入 TIME-WAIT。同一对地址和端口上立刻再开一条,可能碰见这段等待,也可能因实现接受了新的 SYN 而重开。不能从「协议跑在 TCP 上」推出每一次重连都会失败,也不能推出等待一定是 4 分钟。

外层是 UDP 时,没有 FIN,也没有 TIME-WAIT。空闲之后映射还在不在,是另一件事,见 保活与掉线重连。保活维持的是一条尚未关闭的会话或中间设备上的映射。TIME-WAIT 开始于已经发出关闭之后。

内层 TCP 的两端仍是应用程序和它的对端。封装把段装进隧道,不删除任何一端的控制块。用户主动关闭内层连接时,主动的那一端可以在 TIME-WAIT 里继续占着这一对套接字,即使隧道图标已经变化。隧道断开若导致内层收到重置或不再有确认,走的是重置或重传超时,不是这份 2 倍 MSL 的正常关闭。外层用 TCP 还是 UDP,见 VPN 用 TCP 还是 UDP。

重放保护 看的是隧道报文的编号窗口。TIME-WAIT 看的是同一对 TCP 套接字的上一次化身。通过其中一层,不表示另一层的旧段也会被收下。

本文不提供缩短 TIME-WAIT、复用本地端口或调整系统参数的步骤。

现象对照

现象更可能先看什么
只有发出第一个 FIN 的那一端还留着这条连接主动关闭进入 TIME-WAIT,被动关闭可以已经是 CLOSED
对端又送来同一个 FIN,等待被延长TIME-WAIT 里确认 FIN 重传,并重新开始 2 倍 MSL
同一对端口很快又能连上实现可能接受了新 SYN,或等待已经结束。规范里的 4 分钟不是测量值
外层是 UDP,重连不再报「地址正被使用」这一层没有 TIME-WAIT。内层 TCP 仍可能另有等待
关闭很干净,但旧段没有被新连接收下化身隔离仍在起作用。这和隧道重放窗口不是同一套编号

核对清单

  1. 先看谁发了第一个 FIN:主动关闭的一端必须停留 2 倍 MSL;
  2. 4 分钟是规范里的工程选择:MSL 取 2 分钟。某一系统等不等这么久,要另测;
  3. FIN 重传会重新计时:等待可以因此变长;
  4. 接受新 SYN 是 MAY:初始序号必须更大,旧副本要退回 TIME-WAIT;
  5. UDP 外层没有这个状态:内层 TCP 的 TIME-WAIT 也不会被封装清掉。