连载中 4/20

三次握手:为什么偏偏是三次,两次不行吗

2026-10-02 · 30 阅读 · 0 评论 · 0 赞

三次握手全过程

客户端调 connect(),三次报文往来,连接才算立住:

客户端                          服务端
   │ ① SYN, seq=x                 │
   │ ────────────────────────────→ │  服务端进入 SYN_RCVD
   │                               │  半连接队列 +1
   │ ② SYN+ACK, seq=y, ack=x+1    │
   │ ←──────────────────────────── │
   │ ③ ACK, ack=y+1               │
   │ ────────────────────────────→ │  移入全连接队列
   │ 客户端 ESTABLISHED            │  服务端 ESTABLISHED

// 初始序号 ISN(x 和 y)是随机的,不是从 0 开始
// 目的:防止上一次连接的旧报文混进新连接

报文里的 seq 是我这个方向的数据从第几字节开始,ack 是我期待对方下一个字节从第几开始(等于收到的字节数 + 1)。TCP 的一切可靠传输,都建立在这两个数字的对账上。

为什么偏偏是三次

先明确握手要达成什么:双方都要确认自己和对方的收发能力都正常。一次做不到,两次有个致命漏洞:

两次握手的问题:迟到的旧 SYN
  客户端发了一个 SYN( seq=100 ),网络堵塞,它滞留在路上
  客户端超时重发新 SYN,完成连接,干完活,正常断开
  那个旧 SYN 终于到达服务端——

  两次握手:服务端回个 ACK 就当连接建立,傻等数据,资源被占死
  三次握手:服务端回 SYN+ACK 后还要等客户端的最终 ACK
           客户端一看 ack 对不上自己的状态,回 RST,连接作废 ✓

三次的本质:服务端把连接建立这件事的决定权留到收到客户端最终确认为止。四次则没必要——SYN 和 ACK 可以合并成一个报文,合并了正好三次。

半连接队列与 SYN Flood

服务端收到 SYN 后先把连接放进半连接队列,等第三次 ACK 才挪进全连接队列。攻击者专打这里:海量 SYN 只发第一步不回第三步(伪造源地址,服务端的 SYN+ACK 根本送不到真人手里),半连接队列被灌满,正常用户连不上——这就是 SYN Flood。两个参数是常规防御:

$ cat /proc/sys/net/ipv4/tcp_syncookies    # 1 = 开启 syncookies
$ cat /proc/sys/net/ipv4/tcp_max_syn_backlog  # 半连接队列长度

# syncookies 思路:队列满了不再排队,把连接信息编进 SYN+ACK 的序号里
# 第三次 ACK 回来时验算通过就直接建立连接——用算术换空间,攻击者的伪造 ACK 算不出来

握手成本:连接池的由来

一次握手 = 一个 RTT 的延迟 + 内核资源。北京到广州 RTT 约 30ms,短连接每次请求都白付 30ms 建立费,高 QPS 下还要叠加端口、队列、上下文的开销。所以数据库有连接池、HTTP 有 keepalive、RPC 框架有长连接——都是在摊薄握手成本。后面讲长连接复用时,会算这笔账。面试若追问 ISN 为什么随机:防止上一个四元组相同的历史连接残留报文被误认,也增加伪造难度。下一篇:握手好聚,散伙难——四次挥手和缠人的 TIME_WAIT。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#三次握手#TCP连接#SYN Flood#半连接队列#ISN

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10100 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9872 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9293 阅读 · 21 评论 · 287 赞