Skip to content
进阶

一句话答案

主动关闭方进入 TIME_WAIT 等 2MSL,确保最后 ACK 到达且旧报文消亡;高并发短连接时大量 TIME_WAIT 需优化。

核心要点

TIME_WAIT:

  • 发生在主动关闭方(通常是客户端),发出第4次 ACK 后进入
  • 等待时间:2MSL(Maximum Segment Lifetime,报文最大存活时间,Linux 默认约 60s)

为什么要等 2MSL:

  1. 保证最后一个 ACK 能到达对方:若 ACK 丢失,服务端会重发 FIN;2MSL 内可以重新响应
  2. 让网络中残留的旧报文消失:防止旧连接的延迟报文被新连接误接收

TIME_WAIT 过多的问题:

  • 大量 TIME_WAIT 占用端口(每个 TIME_WAIT 占用一个四元组),可能耗尽可用端口
  • 高并发短连接场景(如 HTTP/1.0)容易出现

解决:

bash
# Linux 内核参数
net.ipv4.tcp_tw_reuse = 1   # 允许 TIME_WAIT socket 用于新连接(需满足条件)
net.ipv4.tcp_fin_timeout = 30  # 减少 FIN_WAIT_2 等待时间

CLOSE_WAIT:

  • 发生在被动关闭方(服务端),收到对方 FIN 后发出 ACK,等待本地应用程序关闭连接

出现大量 CLOSE_WAIT 的根本原因:

  • 服务端代码没有调用 socket.close(),即连接没有被正确关闭

常见代码原因:

java
// 错误:没有在 finally 中关闭连接
try {
    InputStream in = socket.getInputStream();
    // 处理数据
} catch (Exception e) {
    log.error(e);
    // ❌ 没有 close!
}

// 正确:
try (Socket socket = ...) {  // try-with-resources 自动关闭
    ...
}

排查方法:

bash
netstat -an | grep CLOSE_WAIT | wc -l   # 统计 CLOSE_WAIT 数量
# 大量 CLOSE_WAIT → 检查服务端代码是否有资源未关闭(连接池泄漏)
追问与易错

追问方向:

  • TIME_WAIT 过多怎么优化?
  • 2MSL 具体是多久?
  • tcp_tw_reuse 安全吗?

易错点:

  • ❌ TIME_WAIT 是异常状态——是正常的 TCP 关闭流程
  • ❌ 直接设 tcp_tw_recycle——在 NAT 环境会导致连接异常

💡 记忆锚点

TIME_WAIT像退房后酒店保留房卡2小时(2MSL):一是防你落了东西回来取(最后ACK丢了对方重发FIN),二是等前一位客人的外卖别送到新客人手上(旧报文消亡)。高并发短连接场景TIME_WAIT太多会耗尽端口,用tcp_tw_reuse允许复用。CLOSE_WAIT过多则是服务端忘了关门(没调close)。