面试必考考点!90%开发者误解的
TIME_WAIT,今天一次讲清。
-
第一次挥手(FIN)
- Client发送
FIN包:“我要关闭了”(不再发数据) - 状态变化:
ESTABLISHED → FIN_WAIT_1
- Client发送
-
第二次挥手(ACK)
- Server立即回复
ACK:“收到关闭请求” - 状态变化:
CLOSE_WAIT(此时Server可能还有数据要发送)
- Server立即回复
-
第三次挥手(FIN)
- Server发
FIN包:“我也关闭了”(数据已发完) - 状态变化:
LAST_ACK(等最后一个ACK)
- Server发
-
第四次挥手(ACK)
- Client回复
ACK后进入TIME_WAIT - Server收到
ACK后立即关闭连接
- Client回复
关键状态说明
-
CLOSE_WAIT- 服务端状态,表示等待程序关闭连接
- 问题:大量出现 → 代码未执行
socket.close()
-
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
为什么需要四次挥手?
- 第一次:客户端说“我说完了”
- 第二次:服务端说“知道了”(但服务端可能还有话要说)
- 第三次:服务端说“我也说完了”
- 第四次:客户端说“好的,再见”
核心原则:TCP是双向通道,两边需要分别关闭
实际开发注意
-
写网络程序时,务必在finally中关闭连接:
// Java示例 try { Socket socket = new Socket("host", port); // 业务代码... } finally { socket.close(); // 必须关闭! } -
高并发服务建议:
# Linux优化(减少TIME_WAIT时间) sysctl -w net.ipv4.tcp_fin_timeout=30 # 默认60秒→改为30秒
一句话总结:
四次挥手 = 两次双向确认
核心状态 = CLOSE_WAIT(代码问题) 和 TIME_WAIT(正常等待)
理解这个流程,能解决90%的连接关闭问题!