无知的 TonySeek

Yet Another Seeker

TCP TIME-WAIT 笔记 - 概览

这是我阅读 Vincent Bernat 的 Coping with the TCP TIME-WAIT state on busy Linux servers 一文整理的笔记。虽然是消化过再表述, 但是仍然一篇(阅读 2 分钟)写不完的感觉, 所以先把概览整理了出来, 即 "TIME-WAIT 是个啥" 。

首先得放个 TCP 状态机图:

TCP 状态机

怎样的连接会进入 TIME-WAIT

首先观 TCP 状态机可得到一点: 被动断开连接的一方结束连接前只会依次进入 CLOSE-WAITLAST-ACK 两个状态, TIME-WAIT 永远只出现在主动断开连接的一方 。此外, 非正常断开连接的方式 (例如发送 RST 断开连接) 不经历四次握手, 也不会有 TIME-WAIT 状态。

TIME-WAIT 的连接占用了什么

一个 TCP 连接由四元组确立(源 IP、源端口、目标 IP、目标端口), 所以同一个四元组结束一个连接期间如果进入了 TIME-WAIT 状态, 那么同一四元组当然是不能再被用于新的连接——直到回归 CLOSED 状态。

所以, TIME-WAIT 状态的连接至少占用了四元组。

为什么要有 TIME-WAIT

然后就是为什么要设计这个 TIME-WAIT 状态, 有两个原因:

首先, TIME-WAIT 持续时间为 2*MSL, 其中 MSLTCP 分段的最大寿命, 等待了这段时间再中止连接可以确保新的连接复用同一四元组时 不会收到前一个连接的分段 。为什么经历了 FIN-ACK 握手还会有前一个连接的分段乱入呢?因为传输层之下是网络层, 同一连接的分段可能经由不同的路由被传输。如果一个分段因为拥堵等原因延迟了, 对等实体并不知道, 没等到 ACK 就简单重发了事。而姗姗来迟的分段如果没有经历 TIME-WAIT 这段时间而被蒸发掉, 完全是有可能乱入到新的连接中的。

其次, 被动关闭连接一方发出 FIN 之后会进入 LAST-ACK 状态。如果最后一个 ACK 丢失, 主动关闭连接一方的 TIME-WAIT 占住了坑, 就留下了足够的时间让对方补发 FIN, 或最终超出最大重试次数(最大重试时间)而双方结束连接。如果不占这个坑, 有可能被动关闭方还停留在 LAST-ACK 状态时主动方就结束了连接, 同一四元组再被建立起新连接的时候, 三次握手的 SYN 将被处于 LAST-ACK 状态的(前)被动关闭连接方以 RST 回应, 造成“这个端口坏掉了, 刚握手就被重置连接”的现象。

所以默认情况下, 还必须得保留这个 TIME-WAIT 状态且为足料的 2*MSL 时长。

TCP TIMT-WAIT

Comments