极高 进阶
TCP三次握手与四次挥手#
一句话答案#
三次握手建立连接(SYN→SYN+ACK→ACK),四次挥手关闭连接(FIN→ACK→FIN→ACK),确保双方可靠通信。
核心要点
三次握手过程:
客户端 服务端
│── SYN(seq=x)──────────────→│ 第1次:客户端请求建立连接
│← SYN-ACK(seq=y, ack=x+1)──│ 第2次:服务端确认,同时发起自己的 SYN
│── ACK(ack=y+1)────────────→│ 第3次:客户端确认服务端的 SYN
│ │
├──────── 连接建立,可以传数据 ──┤plaintext为什么需要三次,而不是两次?
防止”历史失效连接请求”造成资源浪费:
场景(只有两次握手的问题):
T1: 客户端发出 SYN1(因网络延迟,迟迟未到达服务端)
T2: 客户端超时,重发 SYN2,正常建立连接,用完后关闭
T3: 延迟的 SYN1 终于到达服务端
→ 两次握手:服务端收到 SYN1,发 SYN-ACK,认为连接建立
→ 服务端分配资源,等待客户端数据
→ 客户端早已关闭,不会响应(连接对客户端来说是"失效的")
→ 服务端的资源白白占用(直到超时释放)plaintext三次握手的第三次 ACK 的作用:
- 让服务端确认客户端”此时仍然活着且愿意建立连接”
- 如果第三次 ACK 没来(历史 SYN),服务端的 SYN-ACK 没有响应,服务端不会维持连接状态
三次握手还确认了双方的初始序列号(ISN):
- 服务端知道客户端的初始序列号(x)
- 客户端知道服务端的初始序列号(y)
- 双方都能确认对方”收到了我的 SYN”,保证了双向通信能力
为什么不需要四次?
- 服务端可以在一个报文里同时发 SYN + ACK(合并为 SYN-ACK),节省一次握手
面试回答(2分钟版)
三次握手的过程是:客户端发SYN报文携带初始序列号x,服务端回复SYN-ACK携带自己的初始序列号y并确认ack=x+1,客户端再发ACK确认ack=y+1,连接建立。为什么必须三次而不是两次,核心原因是防止历史失效连接请求导致服务端资源浪费。假设只有两次握手,客户端之前发的一个延迟SYN到达服务端,服务端回SYN-ACK就认为连接建立了,分配资源等待数据,但客户端早已关闭不会响应,资源就白白占用。三次握手的第三次ACK让服务端确认客户端此刻仍然活着且愿意通信。同时三次握手也完成了双方初始序列号ISN的同步,保证后续可靠传输。四次挥手多一次的原因是TCP是全双工的,收到对方FIN后只是表示对方不再发数据,自己可能还有数据要发完,所以ACK和FIN分成两次发送,中间存在半关闭状态。关闭发起方最后进入TIME_WAIT状态等待2个MSL,确保最后的ACK能到达对方。
追问与易错
追问方向:
- “为什么握手三次不是两次?”→ 防止历史失效的 SYN 到达服务端导致资源浪费,第三次 ACK 让服务端确认客户端此刻仍活跃且愿意通信
- “为什么挥手需要四次?”→ TCP 全双工,收到 FIN 只表示对方不发了,自己可能还有数据要发完,ACK 和 FIN 之间存在半关闭状态所以不能合并
- “SYN Flood 攻击原理和防护?”→ 伪造源 IP 发大量 SYN 填满半连接队列;防护用 tcp_syncookies(不分配队列资源用 cookie 验证)+ 调大 SYN 队列 + 防火墙过滤
易错点:
- ❌ “三次握手是为了可靠”——更准确说是为了同步双方的初始序列号
- ❌ “第三次握手不能携带数据”——可以的,此时客户端已确认连接建立