TCP 三次握手与四次挥手

network 📚 learning tcp-handshake-teardown · network · tcp · handshake · teardown · state-machine · syn · ack · fin · time-wait

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 · 底层(状态机 + 报文)

三次握手(建连):
#报文标志位发送方状态接收方状态
1SYN seq=xSYN=1SYN_SENTLISTEN
2SYN+ACK seq=y ack=x+1SYN=1,ACK=1SYN_SENTSYN_RCVD
3ACK ack=y+1ACK=1ESTABLISHEDSYN_RCVD → ESTABLISHED
四次挥手(断开):
#报文发送方状态接收方状态
1FINFIN_WAIT_1ESTABLISHED
2ACKFIN_WAIT_2CLOSE_WAIT
3FINFIN_WAIT_2LAST_ACK
4ACKTIME_WAITCLOSED(收到 ACK 后)
为什么是三次不是两次:如果客户端 SYN 在网络中延迟到达,服务端回 SYN+ACK 但客户端不会理睬,服务端却进入 ESTABLISHED 状态浪费资源。三次握手中客户端收到迟到的 SYN+ACK 会回 RST 拒绝。 为什么是四次不是三次:TCP 全双工,两个方向独立关闭。被动方收到 FIN 后可能还有数据要发完,所以 ACK 和 FIN 不能合并——ACK 表示"我知道你要关了",FIN 表示"我也发完了"。 TIME_WAIT 为什么等 2MSL:
  • 保证最后一个 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 限速

关联题目

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

  • TCP vs UDP 核心差异
  • 握手 3 次因双向确认,挥手 4 次因全双工分开关;TIME_WAIT 2MSL 双目的
    ✦ 记 忆 口 诀 ✦
    握手 3 次双向确认 / 挥手 4 次全双工分开关 / TIME_WAIT 防丢+消亡
    关键可视化
    暂无可视化
    知识关系

    ⬆️ 前置(Prerequisite)

    暂无

    🔄 延伸(Extends)

    暂无

    ⚡ 对比(Contrast)

    暂无
    🎯 概念 📏 规则 ⚠️ 误区 🔍 追问 ✨ 口诀 共 0 张卡,点击翻面