重要
三次握手建立连接,四次挥手释放连接。握手多一次是历史遗留连接的防御,挥手多一次是因为 TCP 全双工——双方各需要一个 FIN + ACK。
1. 标志位速查
| 标志 | 含义 |
|---|
| SYN | 同步序号,建立连接时使用 |
| ACK | 确认号有效(连接建立后所有报文都必须置 1) |
| FIN | 发送方数据已发送完毕,请求释放连接 |
| seq | 本报文段第一个数据字节的序号 |
| ack | 期望收到对方下一个字节的序号 |
2. 三次握手
1
2
3
4
5
6
7
8
9
| Client Server
| |
|--- SYN=1, seq=x ----------------> | SYN_SENT → SYN_RCVD
| |
|<-- SYN=1, ACK=1, ack=x+1, seq=y -- | SYN_RCVD
| |
|--- ACK=1, ack=y+1 --------------> | ESTABLISHED
| |
ESTABLISHED ESTABLISHED
|
| 次数 | 方向 | 内容 | 目的 |
|---|
| 1 | C → S | SYN, seq=x | 请求建立连接 |
| 2 | S → C | SYN+ACK, seq=y, ack=x+1 | 确认收到,同时发起反向连接请求 |
| 3 | C → S | ACK, ack=y+1 | 确认服务端的连接请求 |
为什么是三次而非两次
两次握手的漏洞:客户端发 SYN-1,网络超时重发 SYN-2。连接建立、通信完成、释放后,SYN-1 才抵达服务端。服务端回 SYN+ACK,认为连接已建立,但客户端已不认这个连接——造成服务端资源浪费。
三次握手中,SYN-1 到达后服务端回 SYN+ACK,客户端不会再回 ACK,服务端收不到确认则不会建立连接。
3. 四次挥手
1
2
3
4
5
6
7
8
9
10
11
| Client Server
| |
|--- FIN=1, seq=x ----------------> | FIN_WAIT_1 → CLOSE_WAIT
| |
|<-- ACK=1, ack=x+1, seq=y -------- | FIN_WAIT_2 → CLOSE_WAIT
| |
|<-- FIN=1, ACK=1, ack=x+1, seq=z-- | FIN_WAIT_2 → LAST_ACK
| |
|--- ACK=1, ack=z+1 --------------> | TIME_WAIT → CLOSED
| |
TIME_WAIT (2MSL) → CLOSED CLOSED
|
| 次数 | 方向 | 内容 | 目的 |
|---|
| 1 | C → S | FIN, seq=x | 客户端不再发送数据 |
| 2 | S → C | ACK, ack=x+1 | 确认收到 FIN |
| 3 | S → C | FIN+ACK, seq=z, ack=x+1 | 服务端也发完数据,请求关闭 |
| 4 | C → S | ACK, ack=z+1 | 确认服务端 FIN,进入 TIME_WAIT |
为什么挥手多一次
TCP 是全双工——双方各自独立关闭。服务端收到 FIN 后,可能还有数据未发完,所以 ACK 和 FIN 分开发送,多了一次。
为什么 TIME_WAIT 要等 2MSL
| 原因 | 说明 |
|---|
| 可靠关闭 | 最后一条 ACK 可能丢失,服务端重发 FIN,客户端在 2MSL 内还能收到并重发 ACK |
| 清除旧报文 | 让本次连接的所有残余报文从网络中消失,防止干扰下一个使用相同端口的新连接 |
参考