TCP四次挥手:3分钟看懂连接关闭

116 阅读2分钟

面试必考考点!90%开发者误解的TIME_WAIT,今天一次讲清。

  1. 第一次挥手(FIN)

    • Client发送FIN包:“我要关闭了”(不再发数据)
    • 状态变化ESTABLISHED → FIN_WAIT_1
  2. 第二次挥手(ACK)

    • Server立即回复ACK:“收到关闭请求”
    • 状态变化CLOSE_WAIT(此时Server可能还有数据要发送)
  3. 第三次挥手(FIN)

    • Server发FIN包:“我也关闭了”(数据已发完)
    • 状态变化LAST_ACK(等最后一个ACK)
  4. 第四次挥手(ACK)

    • Client回复ACK后进入TIME_WAIT
    • Server收到ACK立即关闭连接

关键状态说明

  1. CLOSE_WAIT

    • 服务端状态,表示等待程序关闭连接
    • 问题:大量出现 → 代码未执行socket.close()
  2. TIME_WAIT

    • 客户端状态,等待2MSL时间(通常1-4分钟)
    • 作用:防止最后一个ACK丢失
    • 问题:过多会导致端口耗尽

最常见两个问题

问题1:服务端卡在CLOSE_WAIT
原因:服务器程序没有关闭连接
解决:检查代码是否漏写close()方法

问题2:客户端TIME_WAIT过多
解决命令(Linux服务器):

# 允许复用TIME_WAIT连接
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

为什么需要四次挥手?

  1. 第一次:客户端说“我说完了”
  2. 第二次:服务端说“知道了”(但服务端可能还有话要说)
  3. 第三次:服务端说“我也说完了”
  4. 第四次:客户端说“好的,再见”

核心原则:TCP是双向通道,两边需要分别关闭


实际开发注意

  1. 写网络程序时,务必在finally中关闭连接:

    // Java示例
    try {
      Socket socket = new Socket("host", port);
      // 业务代码...
    } finally {
      socket.close(); // 必须关闭!
    }
    
  2. 高并发服务建议:

    # Linux优化(减少TIME_WAIT时间)
    sysctl -w net.ipv4.tcp_fin_timeout=30  # 默认60秒→改为30秒
    

一句话总结
四次挥手 = 两次双向确认
核心状态 = CLOSE_WAIT(代码问题) 和 TIME_WAIT(正常等待)

理解这个流程,能解决90%的连接关闭问题!