TCP 协议实战:握手、挥手与连接排障
TCP 协议实战:握手、挥手与连接排障
TCP 是面试必问、排障必用的核心协议。三次握手为什么是三次?大量 CLOSE_WAIT 怎么办?这篇把原理和排障串成一条线,附抓包实证。
一、TCP vs UDP:先分清楚
| 特性 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接(三次握手) | 无连接 |
| 可靠 | 可靠(确认重传) | 不可靠 |
| 效率 | 低 | 高 |
| 应用 | HTTP/HTTPS、邮件、FTP | DNS(53)、视频流、语音、DHCP |
类比记忆:TCP 是”外卖必须送到你手里(有确认)”,UDP 是”放门口就走(无确认)”。端口范围 1~65535。
二、三次握手(原理 + 抓包)
1 | 客户端 C 服务端 S |
三个关键点(面试背诵版):
- SYN 报文不携带数据,但消耗一个序列号;
- 第 2 次握手把”确认 ACK”和”请求 SYN”合并成一个报文——所以是三次不是四次;
- seq/ack 都 +1 是确认机制核心:
ack = 对方 seq + 1,表示”下次该收 x+1 了”。
抓包实证(tcpdump 抓 80 端口)看三个包的 seq/ack 严格递进——第 2 个包 ack = 第 1 个包 seq+1。
为什么不能只有两次握手? 场景:客户端发出 SYN 在网络滞留,超时重发后正常完成连接并释放;此时滞留的旧 SYN 才到达服务端——如果只有两次握手,服务端会为这个”已失效的请求”建立连接并一直占用资源。三次握手里,服务端发出 SYN+ACK 后必须等客户端的 ACK 才建立——客户端没发新请求就不会回 ACK,服务端等不到就自动放弃。一句话:两次握手无法确认”客户端能收到服务端的报文”,也无法拒绝失效的旧请求。
三、四次挥手与 2MSL
1 | 客户端 C 服务端 S |
为什么挥手 4 次而握手 3 次? 握手时服务端可以把”确认+请求”合并成一个包(SYN+ACK);挥手时服务端收到 FIN 后可能还有数据要发,不能立刻 FIN,必须先 ACK 再等数据发完单独 FIN——所以多一次。
挥手后客户端为什么要等 2MSL(Linux 默认约 60s)?
- 最后的 ACK 可能丢失——服务端没收到会重发 FIN,客户端在 TIME_WAIT 期间还能再回一次 ACK;
- 保证旧报文在网络中彻底消失,不会污染新连接。
四、连接状态与生产排障(重点)
1 | ss -tulnp # 查看连接状态统计 |
三类生产高频异常:
| 状态 | 含义 | 处理 |
|---|---|---|
| 大量 CLOSE_WAIT | 对端关了,应用没关连接(代码层泄漏) | 查应用:Java 连接池泄漏、请求未关闭;ss -lnt | grep CLOSE_WAIT 确认,修代码/调连接池 |
| 大量 TIME_WAIT | 主动断开方等待 2MSL | 高并发短连接的正常现象;用 keep-alive 连接复用减少;net.ipv4.tcp_tw_reuse=1 谨慎开启 |
| 大量 SYN_RCVD | 收到 SYN 未完成握手,半连接堆积 | 可能被 SYN 洪水攻击;查半连接队列 ss -lnt | grep SYN,上限 net.ipv4.tcp_max_syn_backlog,配合防火墙限速 |
连接不上的四步排查(任何”连不上”都按这个顺序):
1 | 1. ss -lnt # 服务有没有监听 |
TCP 的问题说到底是”连接建不起来(握手)”和”连接关不掉(挥手/资源泄漏)”两类。把状态机和排障命令对应起来,大部分网络故障都能落地到具体的一层。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 LuminDream's Blogs!


