TCP 三次握手与四次挥手
三次握手是每本教材的第一章,但落到生产里的问题——SYN 洪水、TIME_WAIT 堆积、backlog 打满——都需要真正理解状态机才能排查。
三次握手为什么是三次
客户端 服务端
│ ── SYN, seq=x ──→ │ SYN_SENT → 服务端 SYN_RCVD
│ ←─ SYN+ACK ────── │
│ seq=y, ack=x+1
│ ── ACK, ack=y+1 ─→ │ ESTABLISHED 双方
两次不够:服务端需要确认「客户端收到了我的 SYN+ACK」,否则无法区分「旧连接的重复 SYN」(历史失效报文)与「新连接」。第三次 ACK 就是这个确认。序列号的意义正在于此:每个方向的字节流都有编号,确认号表示「期望收到的下一个字节」,重复与乱序由此可判。
四次挥手与 TIME_WAIT
断开需要四次,因为 TCP 是全双工,每个方向独立关闭。主动关闭方最后进入 TIME_WAIT,停留 2MSL(通常 60 秒),原因有二:确保最后一个 ACK 若丢失、对方重发的 FIN 能被响应;让旧连接的报文在网络中自然消亡,避免污染下一个相同四元组的新连接。
高并发短连接服务(爬虫、压测机)会出现几万 TIME_WAIT。它们占用端口但不占应用资源,通常无需处理;确实堆积时优先改用长连接,而不是去改 tcp_tw_reuse。
两个运维落点
SYN 洪水:攻击者发 SYN 不回 ACK,服务端半连接队列被占满。内核参数 tcp_syncookies=1 用加密 Cookie 无状态应答,是标准防御。
backlog 打满:全连接队列(accept 队列)满时新连接被丢。现象是「偶发连接超时」。检查:
ss -lnt | grep :443 # Recv-Q 接近 Send-Q 就是打满
netstat -s | grep -i listen # 看 overflow 计数是否增长
调大 somaxconn 与应用的 listen backlog,并确认应用 accept 速度跟得上——队列是缓冲不是解药。
抓包验证
tcpdump -i any port 443 -nn 直接看 SYN/SYN+ACK/ACK 与挥手序列。教科书上的状态图,在真实报文里对一遍,比背十遍都牢。