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 仍可能另有等待 |
| 关闭很干净,但旧段没有被新连接收下 | 化身隔离仍在起作用。这和隧道重放窗口不是同一套编号 |
核对清单
- 先看谁发了第一个 FIN:主动关闭的一端必须停留 2 倍 MSL;
- 4 分钟是规范里的工程选择:MSL 取 2 分钟。某一系统等不等这么久,要另测;
- FIN 重传会重新计时:等待可以因此变长;
- 接受新 SYN 是 MAY:初始序号必须更大,旧副本要退回 TIME-WAIT;
- UDP 外层没有这个状态:内层 TCP 的 TIME-WAIT 也不会被封装清掉。