---
title: TCP 三次握手与四次挥手
type: concept
domain: network
tags: [network, tcp, handshake, teardown, state-machine, syn, ack, fin, time-wait]
status: learning
created: 2026-09-27
last_reviewed: 2026-09-27
method: feynman
related_questions:
  - "什么是TCP三次握手、四次挥手？"
related_knowledge:
  - ./tcp-udp-comparison.md
anki_cards: 6
interview_rounds:
  - "2026-09-27-round-1-Q2"
---

# TCP 三次握手与四次挥手

> 握手是三次因为"要确认双向收发"；挥手是四次因为"全双工要分开关"。TIME_WAIT 存在 2MSL 是为了防 ACK 丢失 + 让旧报文消亡。

## TL;DR（30 秒扫完）

- **三次握手**：SYN → SYN+ACK → ACK，三次是最少可靠交互次数（每次双向确认收发能力）
- **四次挥手**：FIN → ACK → FIN → ACK，四次因为 TCP 全双工，被动方可能还有数据要发完
- **TIME_WAIT**：主动关闭方等 2MSL（Linux 默认 60s），保证 ACK 到达 + 让旧连接延迟报文消亡
- **异常场景**：SYN Flood 打满半连接队列、TIME_WAIT 过多、CLOSE_WAIT 堆积

## 关键结论

- **结论 A**：握手 = 3 次是因为每次交互双方各确认一次，3 次是最少可靠握手次数
- **结论 B**：挥手 = 4 次是因为 TCP 全双工，被动方收到 FIN 后可能还有数据要发完，ACK 和 FIN 不能合并
- **结论 C**：TIME_WAIT 存在 2MSL 是双重目的（防最后一个 ACK 丢失、让旧报文消亡避免污染新连接）
- **结论 D**：CLOSE_WAIT 堆积 = 应用代码未 close socket，通常是 bug

## 完整讲解（费曼四步）

### STEP 1 · 概念

TCP 是**有连接、全双工**的协议。建连需要三次握手，断开需要四次挥手。

### STEP 2 · 大白话

**握手像加微信**：
1. 我发"加好友请求"（SYN）
2. 你回"请求已收到，也发个请求给你"（SYN+ACK）
3. 我回"已收到你的请求，可以开始了"（ACK）

**挥手像告别**：
1. 我发"我要挂了"（FIN）
2. 你回"我知道了"（ACK，但可能还有话要说）
3. 你说完也发"我也挂了"（FIN）
4. 我回"好的再见"（ACK）

### STEP 3 · 底层（状态机 + 报文）

**三次握手（建连）**：

| # | 报文 | 标志位 | 发送方状态 | 接收方状态 |
|---|------|--------|-----------|-----------|
| 1 | SYN seq=x | SYN=1 | SYN_SENT | LISTEN |
| 2 | SYN+ACK seq=y ack=x+1 | SYN=1,ACK=1 | SYN_SENT | SYN_RCVD |
| 3 | ACK ack=y+1 | ACK=1 | ESTABLISHED | SYN_RCVD → ESTABLISHED |

**四次挥手（断开）**：

| # | 报文 | 发送方状态 | 接收方状态 |
|---|------|-----------|-----------|
| 1 | FIN | FIN_WAIT_1 | ESTABLISHED |
| 2 | ACK | FIN_WAIT_2 | CLOSE_WAIT |
| 3 | FIN | FIN_WAIT_2 | LAST_ACK |
| 4 | ACK | TIME_WAIT | CLOSED（收到 ACK 后） |

**为什么是三次不是两次**：如果客户端 SYN 在网络中延迟到达，服务端回 SYN+ACK 但客户端不会理睬，服务端却进入 ESTABLISHED 状态浪费资源。三次握手中客户端收到迟到的 SYN+ACK 会回 RST 拒绝。

**为什么是四次不是三次**：TCP 全双工，两个方向独立关闭。被动方收到 FIN 后可能还有数据要发完，所以 ACK 和 FIN 不能合并——ACK 表示"我知道你要关了"，FIN 表示"我也发完了"。

**TIME_WAIT 为什么等 2MSL**：
1. 保证最后一个 ACK 到达被动方（如果丢了，被动方会重发 FIN，主动方还在 TIME_WAIT 内可以响应）
2. 让旧连接的所有报文都自然消亡（MSL 是报文最大生存时间），避免污染同一个四元组的新连接

**异常场景**：
- **SYN Flood 攻击**：伪造源 IP 发大量 SYN，服务端半连接队列被打满 → 防御：SYN cookies（`tcp_syncookies=1`）、增加 `tcp_max_syn_backlog`
- **TIME_WAIT 过多**：大量短连接 → 调优：`sysctl.net.ipv4.tcp_tw_reuse=1`（4.12+）、复用连接（HTTP Keep-Alive）
- **CLOSE_WAIT 堆积**：对方已发 FIN 但自己应用未 close()，通常是代码 bug

### STEP 4 · 简化

> **口诀**：握手 3 次因双向确认，挥手 4 次因全双工分开关；TIME_WAIT 2MSL 防 ACK 丢 + 让旧报文消亡。

## 常见误区（从面试记录提炼）

- **误区 1**：只说"确认收发能力"没讲流程 → 正确：必须画出具体报文和状态流转
- **误区 2**："握手四次更好" → 正确：四次是挥手（断开），握手只能三次
- **误区 3**：没解释"为什么是 N 次" → 正确：握手 3 次是最少可靠交互次数；挥手 4 次是因为全双工要分开关

## 延伸追问（面试追问预演）

1. **两次握手为什么不行？**
   - 要点：客户端发的 SYN 如果在网络中延迟，服务端以为要建连回 SYN+ACK，客户端不会理睬；服务端却进入 ESTABLISHED 状态浪费资源。
2. **生产环境大量 TIME_WAIT 怎么办？**
   - 要点：查看 `ss -s`、`netstat -an | grep TIME_WAIT | wc -l`；调 `sysctl.net.ipv4.tcp_tw_reuse=1`；根本方案是复用连接（HTTP Keep-Alive、连接池）。
3. **CLOSE_WAIT 堆积说明什么？**
   - 要点：对方已发 FIN 但自己应用未调用 close()，通常是代码 bug 或 socket 未关闭导致的泄漏。
4. **如何防止 SYN Flood 攻击？**
   - 要点：SYN cookies（`tcp_syncookies=1`）、增加半连接队列 `tcp_max_syn_backlog`、缩短 `tcp_synack_retries`、用 iptables 限速。

## 速查表

```
三次握手：SYN → SYN+ACK → ACK
  状态：SYN_SENT → ESTABLISHED
  目的：确认双向收发能力
四次挥手：FIN → ACK → FIN → ACK
  状态：FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
  目的：全双工分开关
TIME_WAIT：等 2MSL（60s）
  目的：防最后一个 ACK 丢 + 让旧报文消亡
异常：SYN Flood（SYN cookies 防御）/ TIME_WAIT 过多（tcp_tw_reuse）/ CLOSE_WAIT 堆积（代码 bug）
```

## 关联题目（题库）

- [x] 《什么是TCP三次握手、四次挥手？》—— 2026-09-27 Round 1 Q2, 评分 ⭐⭐

## 关联知识

- [TCP vs UDP 核心差异](./tcp-udp-comparison.md)

## Anki 候选卡片

1. **正**：TCP 三次握手分别发什么？状态如何流转？**反**：SYN seq=x → SYN+ACK seq=y ack=x+1 → ACK ack=y+1；状态：LISTEN/SYN_SENT/SYN_RCVD → ESTABLISHED
2. **正**：TCP 四次挥手为什么要四次？**反**：TCP 全双工，被动方收到 FIN 后可能还有数据要发完，ACK 和 FIN 不能合并
3. **正**：TIME_WAIT 为什么要等 2MSL？**反**：保证最后一个 ACK 到达（丢则被动方重发 FIN）+ 让旧连接延迟报文消亡避免污染新连接
4. **正**：两次握手为什么不行？**反**：SYN 延迟会导致服务端进入 ESTABLISHED 但客户端不理睬，浪费资源；三次握手中客户端收到迟到 SYN+ACK 会回 RST
5. **正**：CLOSE_WAIT 堆积说明什么？**反**：对方已发 FIN 但自己应用未 close()，通常是代码 bug 或 socket 未关闭导致的泄漏
6. **正**：SYN Flood 如何防御？**反**：SYN cookies（tcp_syncookies=1）+ 增加 tcp_max_syn_backlog + 缩短 tcp_synack_retries + iptables 限速

---

*最后更新：2026-09-27*
