面试知识库
极高 进阶

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 队列 + 防火墙过滤

易错点:

  • ❌ “三次握手是为了可靠”——更准确说是为了同步双方的初始序列号
  • ❌ “第三次握手不能携带数据”——可以的,此时客户端已确认连接建立