TCP 状态机的 11 个状态,在 netstat 里到底什么时候出现?CLOSE_WAIT 为什么会堆积,TIME_WAIT 留给谁?这篇给回环加延迟,每 20 ms 查一次 netstat,把一次连接从诞生到消失的每个状态和时刻记下来。
场景 1:握手、数据、客户端先 close、服务端晚一秒才 close(单向延迟 150 ms,往返 300 ms;括号里是相对 connect 的时间):
客户端:SYN_SENT(111 ms) → ESTABLISHED(411 ms) → FIN_WAIT_1(1075 ms) → FIN_WAIT_2(1378 ms) → TIME_WAIT(2249 ms)
服务端:SYN_RCVD(263 ms) → ESTABLISHED(580 ms) → CLOSE_WAIT(1222 ms) → LAST_ACK(2110 ms) → (无)(2381 ms)
监听套接字:LISTEN(8 ms)
这个场景里见到的状态:CLOSE_WAIT、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、LAST_ACK、LISTEN、SYN_RCVD、SYN_SENT、TIME_WAIT
场景 2:客户端 connect 之后立刻 close,服务端也立刻 close(看 LAST_ACK)(单向延迟 150 ms,往返 300 ms;括号里是相对 connect 的时间):
客户端:SYN_SENT(118 ms) → ESTABLISHED(405 ms) → FIN_WAIT_1(576 ms) → CLOSING(730 ms) → TIME_WAIT(871 ms)
服务端:SYN_RCVD(254 ms) → FIN_WAIT_1(576 ms) → CLOSING(730 ms) → TIME_WAIT(871 ms)
场景 3:两端同时 close(看 CLOSING)(单向延迟 150 ms,往返 300 ms;括号里是相对 connect 的时间):
一端:SYN_SENT(135 ms) → ESTABLISHED(427 ms) → FIN_WAIT_1(1081 ms) → CLOSING(1241 ms) → TIME_WAIT(1386 ms)
另一端:SYN_RCVD(254 ms) → ESTABLISHED(570 ms) → FIN_WAIT_1(1081 ms) → CLOSING(1241 ms) → TIME_WAIT(1386 ms)客户端 SYN_SENT → ESTABLISHED;服务端 SYN_RCVD → ESTABLISHED,其中 SYN_RCVD 持续一个往返。服务端有没有 accept() 不影响状态。
CLOSED 本次观察到 没有连接(netstat 里没有这一行)
LISTEN 本次观察到 服务端 listen() 之后
SYN_SENT 本次观察到 客户端发出 SYN、等 SYN-ACK
SYN_RCVD 本次观察到 服务端收到 SYN、发出 SYN-ACK、等第三个 ACK
ESTABLISHED 本次观察到 三次握手完成,数据传输阶段
FIN_WAIT_1 本次观察到 主动关闭方发出 FIN、等对方的 ACK
FIN_WAIT_2 本次观察到 主动关闭方的 FIN 已被 ACK,等对方的 FIN
CLOSE_WAIT 本次观察到 被动关闭方收到 FIN、已 ACK,等本端应用 close()
CLOSING 本次观察到 两端同时关闭:发出 FIN 后先收到对方的 FIN
LAST_ACK 本次观察到 被动关闭方发出 FIN、等最后的 ACK
TIME_WAIT 本次观察到 主动关闭方收到对方的 FIN 并回了 ACK,等 2MSL
三个场景里 netstat 抓到了 10 个状态(LISTEN、SYN_SENT、SYN_RCVD、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT、CLOSING、LAST_ACK、TIME_WAIT);CLOSED 本来就是“没有这一行”,算上它是 11 / 11LISTEN、SYN_SENT、SYN_RCVD、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT、CLOSING、LAST_ACK、TIME_WAIT 十个在 netstat 里都能抓到,CLOSED 就是没有这一行。
非阻塞 connect 到一个丢弃 SYN 的地址,0.5 秒后 netstat 看到的状态:['SYN_SENT']
场景 4:非阻塞 connect,服务端不 accept(accept 与状态无关,握手由内核完成)(单向延迟 150 ms,往返 300 ms;括号里是相对 connect 的时间):
客户端:SYN_SENT(127 ms) → ESTABLISHED(432 ms) → FIN_WAIT_1(837 ms) → FIN_WAIT_2(1139 ms)
服务端:SYN_RCVD(279 ms) → ESTABLISHED(579 ms) → CLOSE_WAIT(994 ms)
服务端内核在回了 SYN-ACK 之后到收到客户端第三个 ACK 之前处于 SYN_RCVD;只要握手完成就是 ESTABLISHED——应用有没有调用 accept() 不影响状态,没被 accept 的连接排在全连接队列里(见 backlog 一篇)主动方 FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT;被动方 CLOSE_WAIT(等本端应用 close)→ LAST_ACK → 消失;同时关闭两端 FIN_WAIT_1 → CLOSING → TIME_WAIT。大量 CLOSE_WAIT 说明应用没有及时 close()。