← 返回题目列表

TIME_WAIT 和 CLOSE_WAIT 有什么区别?大量出现怎么办?

高频 中等 第 15 / 30 题 更新于 2026/07/28
TCPTIME_WAITCLOSE_WAIT

简化版

两个都是四次挥手中的状态,但角色相反TIME_WAIT 出现在主动关闭方,是发完最后 ACK 后等 2MSL 的正常状态;CLOSE_WAIT 出现在被动关闭方,是收到对方 FIN、回了 ACK 后、等自己 close() 的状态。大量 TIME_WAIT 通常是短连接太多(正常,可调优);大量 CLOSE_WAIT 几乎一定是代码 bug——收到 FIN 却没调用 close()

详细版

TIME_WAIT(主动关闭方)

  • 发出最后一个 ACK 后进入,等待 2MSLCLOSED
  • 正常且必要的状态,作用是「保证末尾 ACK 送达」+「让旧连接报文消散」(详见「四次挥手」那道题);
  • 大量出现常见于高并发短连接的客户端/主动关闭方(如爬虫、频繁调用下游的服务)。

CLOSE_WAIT(被动关闭方)

  • 收到对方 FIN、自动回了 ACK 后进入,等待自己的应用调用 close() 发出 FIN
  • 会一直停在 CLOSE_WAIT,直到应用 close()
  • 大量堆积 = 应用收到了 FIN 却没有 close 连接,是典型的连接泄漏 bug

完整版教学

一、用角色记住谁在哪一侧

死记状态名容易混,抓住「谁主动关」就清楚了:

  • 主动关闭方(先发 FIN 的一方):经历 FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSEDTIME_WAIT 在主动方。
  • 被动关闭方(后关的一方):经历 CLOSE_WAIT → LAST_ACK → CLOSEDCLOSE_WAIT 在被动方。

这样对照记:主动关的等 2MSL(TIME_WAIT),被动关的等自己 close(CLOSE_WAIT)。

二、TIME_WAIT 为什么必要,又为什么会成问题

必要性(2MSL 的两个作用):

  1. 保证最后的 ACK 能到达对方——万一丢了,对方会重发 FIN,此时还在 TIME_WAIT 就能重新回 ACK;
  2. 让本次连接的旧报文在网络中彻底过期,避免串扰到复用同一四元组的新连接。

为什么会大量出现:TIME_WAIT 要保持 2MSL(通常 1~4 分钟)。如果一个服务频繁地主动关闭大量短连接(比如每次请求都新建 + 主动关一个到下游的连接),这些连接会堆积成成千上万个 TIME_WAIT,占用端口和内存,甚至导致端口耗尽(本地端口不够用,新连接建不了)。

三、大量 TIME_WAIT 怎么办

它是正常状态,思路是「减少 + 复用」而非「消灭」:

  • 根治:改用长连接(连接池复用),减少频繁的建连/关连——这是最有效的办法;
  • net.ipv4.tcp_tw_reuse = 1:允许复用 TIME_WAIT 状态的连接给新的出站连接(需配合时间戳),安全有效;
  • 适当扩大本地端口范围ip_local_port_range);
  • 服务端由客户端主动关闭:把 TIME_WAIT 的负担转移到客户端(谁主动关,TIME_WAIT 就在谁那边)。

⚠️ 老办法 tcp_tw_recycle 在 NAT 环境下会导致丢包,已在新内核移除,不要用

四、大量 CLOSE_WAIT:几乎一定是 bug

CLOSE_WAIT 和 TIME_WAIT 的排查方向完全相反——大量 CLOSE_WAIT 基本就是代码问题

它意味着:对方已经关了连接(发来 FIN,你的内核自动回了 ACK),但你的应用程序迟迟没有调用 close() 去发出自己的 FIN。连接就卡在 CLOSE_WAIT,占着文件描述符不放,越积越多,最终 fd 耗尽、无法接受新连接。

常见原因:

  • 异常路径没有 close()(没放进 finally / try-with-resources);
  • 连接池没有正确回收、归还连接;
  • 阻塞在某处,代码根本走不到 close。

排查:用 netstat/ss 统计 CLOSE_WAIT 数量和对应进程,然后去代码里找「哪条路径漏了 close」。

五、常见误区

  • ❌ 把 TIME_WAIT 和 CLOSE_WAIT 记反——TIME_WAIT 在主动关闭方,CLOSE_WAIT 在被动关闭方。
  • ❌ 想「消灭」TIME_WAIT——它是可靠关闭的必要机制,应减少短连接、开 tcp_tw_reuse,而非粗暴关闭。
  • ❌ 用 tcp_tw_recycle 优化——NAT 下会丢包,已废弃。
  • ❌ 大量 CLOSE_WAIT 去查对端——它在自己这侧,是自己没 close,查自己的代码。

六、常见误区与追问

考点正确口径
TIME_WAIT主动关闭方等待 2MSL
CLOSE_WAIT被动关闭方已收到 FIN,等待应用 close
大量问题TIME_WAIT 多看连接模式,CLOSE_WAIT 多看应用泄漏
active close -> FIN_WAIT -> TIME_WAIT
passive close -> CLOSE_WAIT until app close()

TIME_WAIT 是协议设计的一部分,CLOSE_WAIT 长期堆积更像应用没有把连接关掉。

  • 误区:TIME_WAIT 一定是服务器问题。 谁主动关闭谁进入 TIME_WAIT,客户端和服务端都可能出现。
  • 误区:CLOSE_WAIT 可以靠调内核参数解决。 CLOSE_WAIT 主要是应用未及时 close,根因通常在代码或线程阻塞。
  • 误区:TIME_WAIT 没有任何价值。 它保证最后 ACK 可重传,并避免旧连接报文污染新连接。
  • 追问:大量 TIME_WAIT 怎么处理? 优先使用连接复用、减少短连接,必要时再谨慎调整端口和内核参数。
  • 追问:大量 CLOSE_WAIT 如何定位? 查看进程连接、线程栈、连接池释放逻辑和应用是否处理 EOF/异常。
  • 追问:2MSL 是什么? MSL 是报文最大生存时间,2MSL 覆盖报文和其响应在网络中的最长往返残留。

七、加强记忆

TIME_WAIT 在主动关闭方(发完末 ACK 等 2MSL,正常且必要),CLOSE_WAIT 在被动关闭方(收到 FIN 等自己 close)。大量 TIME_WAIT 多因短连接过多,用长连接/连接池、tcp_tw_reuse 缓解(别用 tcp_tw_recycle);大量 CLOSE_WAIT 几乎必是代码没 close() 的连接泄漏 bug,去查自己的代码。