Java Socket编程:TCP三次握手与四次挥手过程详解
·
Java Socket编程:TCP三次握手与四次挥手详解
一、TCP连接建立(三次握手)
在Java Socket中,当客户端执行new Socket(serverIP, port)时触发三次握手:
- SYN(客户端 → 服务端)
客户端发送SYN包($syn=1, seq=x$),进入SYN_SENT状态 - SYN+ACK(服务端 → 客户端)
服务端响应SYN-ACK包($syn=1, ack=1, seq=y, ack_num=x+1$),进入SYN_RCVD状态 - ACK(客户端 → 服务端)
客户端确认($ack=1, ack_num=y+1$),双方进入ESTABLISHED状态,连接建立
// 客户端触发握手
try (Socket clientSocket = new Socket("192.168.1.100", 8080)) {
// 连接建立后执行操作
}
二、TCP连接终止(四次挥手)
在Java中调用socket.close()时触发四次挥手:
- FIN(主动关闭方 → 被动方)
发送FIN包($fin=1, seq=u$),进入FIN_WAIT_1状态 - ACK(被动方 → 主动方)
被动方确认($ack=1, ack_num=u+1$),主动方进入FIN_WAIT_2状态 - FIN(被动方 → 主动方)
被动方发送FIN包($fin=1, seq=v$),进入LAST_ACK状态 - ACK(主动方 → 被动方)
主动方确认($ack=1, ack_num=v+1$),进入TIME_WAIT(等待2MSL后关闭)
// 服务端关闭连接示例
try (ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept()) {
// 通信结束后关闭
socket.close(); // 触发挥手过程
}
三、关键机制解析
-
序列号保障可靠性
每次传输的序列号满足:$seq_{new} = seq_{old} + data_len$
确认号规则:$ack_num = received_seq + 1$ -
TIME_WAIT状态作用
- 确保最后一个ACK到达(重传丢失的FIN)
- 允许旧报文在网络中消亡(等待2MSL时间)
-
半关闭状态
调用shutdownOutput()时发送FIN,但仍可接收数据,对应四次挥手中的步骤1-2
四、常见问题与解决方案
| 问题现象 | 原因 | 解决方法 |
|---|---|---|
BindException | 端口处于TIME_WAIT | 设置SO_REUSEADDR选项 |
| 连接超时 | SYN包未收到ACK | 检查防火墙/网络配置 |
ConnectionReset | 收到RST包 | 检查对端是否异常关闭 |
重要提示:在Socket编程中需显式关闭资源,避免连接泄漏:
// 推荐写法(Java 7+ try-with-resources)
try (Socket socket = new Socket();
OutputStream out = socket.getOutputStream()) {
// 业务代码
} // 自动调用close()触发四次挥手
五、Wireshark抓包分析
通过抓包工具可观察:
- 握手阶段:SYN → SYN-ACK → ACK
- 挥手阶段:FIN → ACK → FIN → ACK
- 序列号变化符合:$ack_num = seq_{received} + 1$
理解TCP状态机对调试网络问题至关重要,建议结合
netstat -ano命令监控Socket状态变化。
更多推荐


所有评论(0)