← 返回题目列表

TCP 连接状态机是怎么流转的?各状态有什么作用?

高频 困难 第 19 / 30 题 更新于 2026/07/30
TCP状态机连接管理TIME_WAITCLOSE_WAIT

简化版

TCP 状态机描述一条连接从建立、传输到关闭的完整生命周期。面试要抓住三条主线:主动打开走 SYN_SENT,被动打开走 LISTEN/SYN_RECEIVED,主动关闭走 FIN_WAIT_1/FIN_WAIT_2/TIME_WAIT,被动关闭走 CLOSE_WAIT/LAST_ACK

详细版

TCP 常见状态可以按阶段记:

  1. 建连阶段:服务端 LISTEN,客户端发 SYN 后进入 SYN_SENT,服务端收到 SYN 后进入 SYN_RECEIVED,三次握手完成后双方进入 ESTABLISHED
  2. 传输阶段:ESTABLISHED 表示连接可双向收发数据。
  3. 主动关闭:主动发 FIN 的一方进入 FIN_WAIT_1,收到对方 ACK 后进入 FIN_WAIT_2,再收到对方 FIN 并回 ACK 后进入 TIME_WAIT,等待 2MSL 后 CLOSED
  4. 被动关闭:收到 FIN 的一方先回 ACK 并进入 CLOSE_WAIT,等应用调用 close 后发 FIN 进入 LAST_ACK,收到最终 ACK 后 CLOSED
  5. 异常关闭:收到或发送 RST 通常直接释放连接,不走完整 FIN 流程。

面试追问通常会落到 TIME_WAITCLOSE_WAIT:大量 TIME_WAIT 常见于主动关闭连接过多,大量 CLOSE_WAIT 多半是应用没有及时关闭 socket。

完整版教学

一、为什么 TCP 需要这么多状态

TCP 是面向连接的字节流协议,它要在不可靠网络上维护“双方都认为连接处于同一阶段”的共同认知。网络会丢包、乱序、延迟,所以 TCP 不能只用“已连接/未连接”两个状态,否则很难处理半关闭、重复 FIN、迟到报文和异常复位。

可以把 TCP 状态机理解成连接生命周期的账本:每发出一个控制报文,就记录自己下一步在等什么;每收到一个控制报文,就根据当前状态判断是否推进、重传、忽略或复位。

状态 = 当前连接阶段 + 正在等待的对端动作
例如:
FIN_WAIT_1 = 我已经发 FIN,正在等对端 ACK 或 FIN
CLOSE_WAIT = 我收到对端 FIN,已经 ACK,正在等本地应用 close
TIME_WAIT = 我已回最后 ACK,正在等旧报文自然消失

记忆钩子:TCP 状态名不是死记硬背,它们大多在说“我刚做了什么,以及我正在等什么”。

二、建连状态:LISTEN、SYN_SENT、SYN_RECEIVED、ESTABLISHED

服务端先调用 listen,进入 LISTEN,它不是“已经连接”,而是准备接收 SYN。客户端主动发 SYN 后进入 SYN_SENT,意思是“我发起连接了,正在等 SYN+ACK”。服务端收到 SYN 后进入 SYN_RECEIVED,回 SYN+ACK,等待客户端最后的 ACK。

三次握手完成后,双方才进入 ESTABLISHED。这个状态很重要,因为只有它表示连接已经可以稳定双向传输应用数据。

Client                          Server
CLOSED                          LISTEN
  | -- SYN --------------------> |
SYN_SENT                        SYN_RECEIVED
  | <------- SYN + ACK --------- |
  | -- ACK --------------------> |
ESTABLISHED                     ESTABLISHED

举个数字例子:客户端初始序列号 seq=1000,服务端初始序列号 seq=8000。客户端第三次握手里的 ACK=8001 表示服务端的 SYN 已被确认,服务端收到后才认为连接建立完成。

三、正常关闭:主动关闭方为什么会经过 FIN_WAIT 和 TIME_WAIT

TCP 是全双工协议,两个方向的数据流可以独立关闭。主动关闭方发 FIN,只表示“我这边不再发送数据”,不等于对方也没有数据要发。因此主动关闭方收到 ACK 后进入 FIN_WAIT_2,继续等待对方的 FIN。

当主动关闭方收到对方 FIN 后,会回最后一个 ACK 并进入 TIME_WAIT。它不马上消失,是为了处理两个问题:第一,最后 ACK 可能丢失,需要能够重发;第二,网络中旧连接的迟到报文要等到过期,避免污染下一条相同四元组连接。

状态谁更常见含义常见风险
FIN_WAIT_1主动关闭方已发 FIN,等 ACK/FIN对端无响应
FIN_WAIT_2主动关闭方对端 ACK 了我的 FIN,等对端 FIN对端迟迟不关闭
TIME_WAIT主动关闭方已回最后 ACK,等待 2MSL短连接高并发下占端口
CLOSING双方同时关闭双方几乎同时发 FIN较少见

四、被动关闭:CLOSE_WAIT 和 LAST_ACK 重点看应用层

被动关闭方收到 FIN 后,内核会先回 ACK,连接进入 CLOSE_WAIT。这个状态表示“对方不发了,但本地应用还没有调用 close”。所以大量 CLOSE_WAIT 往往不是网络问题,而是应用代码没有释放连接、业务线程卡住、连接池归还逻辑异常。

应用真正调用 close 后,被动关闭方才发 FIN,进入 LAST_ACK,等待主动关闭方的最后 ACK。收到 ACK 后连接关闭。

对端 FIN 到达
    |
    v
内核回 ACK -> CLOSE_WAIT
    |
    | 应用调用 close()
    v
发送 FIN -> LAST_ACK -> 收到 ACK -> CLOSED

排查时可以按数字看:如果某服务长期保持 CLOSE_WAIT=3000,而请求量并没有相应峰值,优先查代码是否没有关闭响应体、socket、数据库代理连接或上游 HTTP 连接。

五、同时关闭和异常关闭怎么理解

如果双方几乎同时调用 close,双方都可能在收到对端 FIN 前先发出自己的 FIN,于是进入 CLOSING。这个状态不常见,但它说明 TCP 的关闭不是单向脚本,而是双方都可能独立行动。

异常关闭主要和 RST 有关。RST 表示连接被重置,通常不会走 FIN_WAITCLOSE_WAITTIME_WAIT 的优雅关闭流程。比如访问一个没有监听的端口、应用强制关闭连接、收到不符合当前状态的报文,都可能触发 RST。

正常关闭:FIN -> ACK -> FIN -> ACK   保留半关闭语义
异常关闭:RST                       直接告诉对端连接不可继续

面试里要把 FIN 和 RST 区分开:FIN 是“我不再发送,但还能收”,RST 是“这条连接作废”。

六、用状态机排查线上问题

状态机不是背概念用的,它能直接指导排障。看到不同状态数量异常,要先判断是主动关闭方多,还是被动关闭方多;是网络迟滞,还是应用没有释放资源。

现象更可能的原因排查方向
TIME_WAIT本机主动关闭短连接多连接复用、端口范围、关闭策略
CLOSE_WAIT应用收到 FIN 后未 close代码释放、线程阻塞、连接池
SYN_SENT对端不可达或被拦截路由、防火墙、目标端口
SYN_RECEIVED握手未完成半连接队列、SYN flood、回包路径
FIN_WAIT_2对端不发 FIN对端应用关闭逻辑

一个常见判断公式是:

主动关闭问题优先看 TIME_WAIT / FIN_WAIT_*
被动关闭问题优先看 CLOSE_WAIT / LAST_ACK
建连问题优先看 SYN_SENT / SYN_RECEIVED

七、常见误区与追问

  • 误区:ESTABLISHED 表示永远可用。 它只表示 TCP 状态已建立,应用层超时、对端崩溃、链路中断仍可能让读写失败。
  • 误区:CLOSE_WAIT 是 TCP 协议缺陷。 多数情况下它暴露的是应用没有调用 close 或资源释放路径被阻塞。
  • 误区:TIME_WAIT 一定是坏事。 它承担重发最后 ACK 和隔离旧报文的作用,数量是否异常要结合短连接规模判断。
  • 追问:为什么主动关闭方进入 TIME_WAIT? 因为主动关闭方发出了最后 ACK,需要在 ACK 丢失时还能重发,并等待旧报文过期。
  • 追问:SYN_RECEIVED 很多说明什么? 说明握手停在服务端收到 SYN 后,可能是半连接队列压力、攻击、回包丢失或客户端异常。
  • 追问:FIN_WAIT_2 很多怎么查? 先确认本机是否主动关闭,再查对端为什么迟迟不发送 FIN,以及是否有超时兜底。

八、加强记忆

把 TCP 状态机串成四段:建连看 LISTEN -> SYN_SENT/SYN_RECEIVED -> ESTABLISHED;主动关闭看 FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT;被动关闭看 CLOSE_WAIT -> LAST_ACK;异常关闭看 RST。面试答题时先画生命周期,再解释 TIME_WAITCLOSE_WAIT 的线上含义,就能从背状态升级到会排障。