TCP 有限状态机
什么是有限状态机
TCP 用**有限状态机(Finite State Machine, FSM)**精确描述连接从建立到释放的全生命周期。共定义 11 种状态,每个状态由特定事件(收到报文、应用层调用、超时)触发转换。
11 种状态详解
| 状态 | 说明 | 典型场景 |
|---|---|---|
| CLOSED | 无连接 | 初始状态或连接完全关闭 |
| LISTEN | 监听 | 服务端等待客户端连接 |
| SYN_SENT | SYN 已发送 | 客户端发送 SYN 后等待回复 |
| SYN_RCVD | SYN 已收到 | 服务端收到 SYN 并回复 SYN-ACK |
| ESTABLISHED | 连接建立 | 数据传输阶段 |
| FIN_WAIT_1 | FIN 已发送 | 主动关闭方发送 FIN 后等待 ACK |
| FIN_WAIT_2 | FIN 已确认 | 收到 ACK,等待对方 FIN |
| CLOSE_WAIT | 收到对方 FIN | 被动关闭方等待应用层关闭 |
| CLOSING | 同时关闭 | 双方同时发送 FIN |
| LAST_ACK | 最后确认 | 被动关闭方发送 FIN 后等待 ACK |
| TIME_WAIT | 等待 2MSL | 确保可靠终止 + 防止旧报文干扰 |
客户端与服务端状态转换对比
客户端:主动发起连接,主动关闭连接,经历 TIME_WAIT 服务端:被动接受连接,被动关闭连接(通常),不经历 TIME_WAIT
异常状态转换
RST 重置连接
收到 RST 报文时,连接立即进入 CLOSED,不经过四次挥手:
触发 RST 的场景:
- 端口未监听(Connection Refused)
- 连接异常(如中间防火墙切断)
- 应用层强制关闭(SO_LINGER 选项)
- 收到不属于任何连接的报文
同时打开与同时关闭
同时打开(双方同时发送 SYN):
CLOSED → SYN_SENT → SYN_RCVD → ESTABLISHED
同时关闭(双方同时发送 FIN):
ESTABLISHED → FIN_WAIT_1 → CLOSING → TIME_WAIT → CLOSED
查看连接状态
# Linux: 查看各状态连接数量
ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn
# 典型输出
500 ESTAB
200 TIME-WAIT
50 CLOSE-WAIT
10 SYN-RECV
5 LISTEN
CLOSE_WAIT 过多:说明服务端应用层没有及时关闭连接(如忘记调用 close()),需检查代码。
SYN_RECV 过多:可能遭受 SYN Flood 攻击。
TIME_WAIT 过多:主动关闭方频繁断连,考虑连接复用。
本篇小结
- TCP 定义 11 种状态,构成有限状态机
- 正常流程:CLOSED → LISTEN/SYN_SENT → SYN_RCVD → ESTABLISHED → FIN_WAIT → TIME_WAIT → CLOSED
- RST 立即终止连接,不经过四次挥手
- 同时打开:双方都走 SYN_SENT → SYN_RCVD → ESTABLISHED
- 同时关闭:双方都走 FIN_WAIT_1 → CLOSING → TIME_WAIT
- 通过
ss -tan监控各状态数量,定位问题
动手实践
查看本机各 TCP 状态数量:
ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn找到处于 CLOSE_WAIT 的连接,查看对应的进程:
ss -tp | grep CLOSE-WAIT用
telnet连接一个不存在的端口,观察 RST 报文(Wireshark 过滤tcp.flags.rst==1)思考:为什么服务端通常不进入 TIME_WAIT?如果服务端主动关闭连接,会有什么后果?