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 不能合并
结论 CTIME_WAIT 存在 2MSL 是双重目的(防最后一个 ACK 丢失、让旧报文消亡避免污染新连接)
结论 DCLOSE_WAIT 堆积 = 应用代码未 close socket,通常是 bug
完整讲解(费曼四步)
STEP 1 · 概念
TCP 是有连接、全双工的协议。建连需要三次握手,断开需要四次挥手。STEP 2 · 大白话
握手像加微信:- 我发"加好友请求"(SYN)
- 你回"请求已收到,也发个请求给你"(SYN+ACK)
- 我回"已收到你的请求,可以开始了"(ACK)
- 我发"我要挂了"(FIN)
- 你回"我知道了"(ACK,但可能还有话要说)
- 你说完也发"我也挂了"(FIN)
- 我回"好的再见"(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 后) |
- 保证最后一个 ACK 到达被动方(如果丢了,被动方会重发 FIN,主动方还在 TIME_WAIT 内可以响应)
- 让旧连接的所有报文都自然消亡(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 丢 + 让旧报文消亡。
常见误区
只说"确认收发能力"没讲流程
必须画出具体报文和状态流转
"握手四次更好"
四次是挥手(断开),握手只能三次
没解释"为什么是 N 次"
握手 3 次是最少可靠交互次数;挥手 4 次是因为全双工要分开关
延伸追问
两次握手为什么不行?
要点:客户端发的 SYN 如果在网络中延迟,服务端以为要建连回 SYN+ACK,客户端不会理睬;服务端却进入 ESTABLISHED 状态浪费资源。
生产环境大量 TIME_WAIT 怎么办?
要点:查看
ss -s、netstat -an | grep TIME_WAIT | wc -l;调 sysctl.net.ipv4.tcp_tw_reuse=1;根本方案是复用连接(HTTP Keep-Alive、连接池)。CLOSE_WAIT 堆积说明什么?
要点:对方已发 FIN 但自己应用未调用 close(),通常是代码 bug 或 socket 未关闭导致的泄漏。
如何防止 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)
Anki 候选卡片
Q: TCP 三次握手分别发什么?状态如何流转?
A: SYN seq=x → SYN+ACK seq=y ack=x+1 → ACK ack=y+1;状态:LISTEN/SYN_SENT/SYN_RCVD → ESTABLISHED
Q: TCP 四次挥手为什么要四次?
A: TCP 全双工,被动方收到 FIN 后可能还有数据要发完,ACK 和 FIN 不能合并
Q: TIME_WAIT 为什么要等 2MSL?
A: 保证最后一个 ACK 到达(丢则被动方重发 FIN)+ 让旧连接延迟报文消亡避免污染新连接
Q: 两次握手为什么不行?
A: SYN 延迟会导致服务端进入 ESTABLISHED 但客户端不理睬,浪费资源;三次握手中客户端收到迟到 SYN+ACK 会回 RST
Q: CLOSE_WAIT 堆积说明什么?
A: 对方已发 FIN 但自己应用未 close(),通常是代码 bug 或 socket 未关闭导致的泄漏
Q: SYN Flood 如何防御?
A: SYN cookies(tcp_syncookies=1)+ 增加 tcp_max_syn_backlog + 缩短 tcp_synack_retries + iptables 限速
关联题目
关联知识
握手 3 次因双向确认,挥手 4 次因全双工分开关;TIME_WAIT 2MSL 双目的
✦ 记 忆 口 诀 ✦
握手 3 次双向确认 / 挥手 4 次全双工分开关 / TIME_WAIT 防丢+消亡
关键可视化
暂无可视化
知识关系
⬆️ 前置(Prerequisite)
暂无🔄 延伸(Extends)
暂无⚡ 对比(Contrast)
暂无
🎯 概念
📏 规则
⚠️ 误区
🔍 追问
✨ 口诀
共 0 张卡,点击翻面