TCP 三次握手与四次挥手笔记
一、TCP 三次握手(建立连接)
TCP 是面向连接的、可靠的传输层协议,为了建立可靠的连接,TCP 采用三次握手(Three-way Handshake)机制。
1.1 三次握手过程
次数 | 发送方 | 接收方 | 说明 |
---|---|---|---|
第一次握手 | 发送 SYN=1,seq=x | 客户端发送连接请求,进入 SYN_SEND 状态 | |
第二次握手 | 发送 SYN=1,ACK=1,seq=y,ack=x+1 | 服务器收到请求,确认后进入 SYN_RCVD 状态 | |
第三次握手 | 发送 ACK=1,seq=x+1,ack=y+1 | 客户端收到确认,进入 ESTABLISHED 状态,服务器收到后也进入 ESTABLISHED |
1.2 报文示意图
客户端 服务器| ----------- SYN ------------> || <-------- SYN + ACK --------- || ----------- ACK ------------> |
连接建立
1.3 握手各个阶段详解
-
第一次握手:
客户端发送一个带 SYN 标志的数据包,表示请求建立连接,包内包含初始序列号seq = x
。 -
第二次握手:
服务器收到 SYN 包,确认(ACK)客户端的 SYN,同时发送自己的 SYN,seq = y
,ack = x+1
。 -
第三次握手:
客户端收到 SYN+ACK,发送 ACK 确认,ack = y+1
。
连接正式建立,双方可以开始数据传输了。
二、为什么需要三次握手?
- 防止历史连接请求造成的错误连接(防止旧的重复连接初始化请求报文被服务器误处理)。
- 确认双方的接收与发送能力均正常。
- 确认客户端的初始序列号,服务器的初始序列号。
三、TCP 四次挥手(释放连接)
TCP 连接释放采用四次挥手(Four-way Handshake)机制,目的是保证双方都能彻底释放连接,避免数据丢失。
3.1 四次挥手过程
次数 | 发送方 | 接收方 | 说明 |
---|---|---|---|
第一次挥手 | 发送 FIN=1,seq=u | 客户端请求关闭连接,进入 FIN_WAIT_1 | |
第二次挥手 | 发送 ACK=1,ack=u+1 | 服务器确认关闭请求,进入 CLOSE_WAIT,客户端进入 FIN_WAIT_2 | |
第三次挥手 | 发送 FIN=1,seq=v | 服务器准备关闭,通知客户端 | |
第四次挥手 | 发送 ACK=1,ack=v+1 | 客户端确认,进入 TIME_WAIT,服务器关闭,最后客户端关闭 |
3.2 报文示意图
客户端 服务器| ----------- FIN ------------> || <----------- ACK ------------ || <----------- FIN ------------ || ----------- ACK ------------> |
连接关闭
3.3 各阶段详解
-
第一次挥手:
客户端主动发送 FIN,表示不再发送数据,进入FIN_WAIT_1
。 -
第二次挥手:
服务器收到 FIN,返回 ACK,进入CLOSE_WAIT
,客户端进入FIN_WAIT_2
。 -
第三次挥手:
服务器处理完剩余事务后,发送 FIN,通知客户端,进入LAST_ACK
。 -
第四次挥手:
客户端确认后,进入TIME_WAIT
,等待 2MSL 后,最终关闭。
四、为什么需要四次挥手?
- TCP 是全双工通信,关闭需要双方单独关闭各自的发送方向。
- 第二次挥手后,服务器可能还有数据未发送完,不能直接关闭,需等待全部发送完成才发 FIN。
五、TIME_WAIT 状态及意义
- 保证最后一个 ACK 能被对方接收到(如果丢失,服务器会重发 FIN)。
- 防止旧连接中的延迟数据影响新连接。
- 通常等待时间是 2 倍的 MSL(Maximum Segment Lifetime)。
六、状态迁移图(简化版)
客户端状态:
CLOSED -> SYN_SENT -> ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> CLOSED服务器状态:
CLOSED -> LISTEN -> SYN_RCVD -> ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED
七、总结对比
建立连接 | 断开连接 |
---|---|
三次握手 | 四次挥手 |
双方都需要确认对方 | 双方都需要关闭发送功能 |
主要防止失效连接请求 | 确保数据完整可靠传输 |
八、附加 — 常见面试考点
-
为什么不是两次握手?
防止失效的连接请求导致的伪连接。 -
为什么不是三次挥手?
因为连接是双向的,必须双方都关闭发送端。 -
TIME_WAIT 为什么必须有?
确保可靠性,避免延迟包干扰。 -
如果客户端 TIME_WAIT 太多怎么办?
- 调整操作系统参数,缩短 TIME_WAIT 时间
- 使用连接复用(如 HTTP Keep-Alive)