题目
TCP三次握手异常场景分析与故障排查
信息
- 类型:问答
- 难度:⭐⭐
考点
TCP连接建立过程, 超时重传机制, 网络故障排查
快速回答
当客户端发送SYN包后未收到SYN-ACK响应时:
- 客户端触发超时重传机制,默认间隔为1s/3s/7s/15s/31s
- Linux系统默认重试5次(约63秒后放弃)
- 排查方向:
- 服务端状态:
netstat -ant检查SYN-RECEIVED队列 - 网络路径:防火墙规则、路由配置
- 抓包分析:
tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0'
- 服务端状态:
一、TCP三次握手标准流程
正常建立连接过程:
- SYN:客户端发送SYN=1, Seq=X
- SYN-ACK:服务端回复SYN=1, ACK=1, Seq=Y, Ack=X+1
- ACK:客户端发送ACK=1, Seq=X+1, Ack=Y+1

二、第二次握手丢失的异常处理
1. 客户端行为(主动方)
// Linux内核重传实现(简化版)
void tcp_syn_retransmit(struct sock *sk) {
if (sk->sk_retries < sysctl_tcp_syn_retries) { // 默认5次
sk->sk_retries++;
timeout = 2 ^ (sk->sk_retries) - 1; // 指数退避
schedule_retransmit(timeout);
} else {
tcp_enter_close(sk); // 关闭连接
}
}重传时间线:
| 重传次数 | 等待时间(s) | 累计时间(s) |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 3 | 4 |
| 3 | 7 | 11 |
| 4 | 15 | 26 |
| 5 | 31 | 57 |
2. 服务端行为(被动方)
- 保持SYN-RECEIVED状态直到超时(默认60s)
- 半连接队列查看命令:
netstat -ant | grep SYN_RECV | wc -l - 队列满时将丢弃新SYN包(SYN Flood攻击防护)
三、故障排查实践
1. 抓包分析示例
# tcpdump捕获重传包
15:30:01.123 IP client:54321 > server:80 [SYN]
15:30:02.126 IP client:54321 > server:80 [SYN] # 第一次重传
15:30:05.129 IP client:54321 > server:80 [SYN] # 第二次重传2. 关键检查点
- 防火墙规则:检查iptables/nftables是否过滤SYN-ACK
iptables -L -n -v | grep DROP - 内核参数调优:
net.ipv4.tcp_syn_retries(客户端重试次数)net.ipv4.tcp_max_syn_backlog(服务端队列长度)
- 中间设备:负载均衡器或NAT会话超时时间配置
四、最佳实践
- 生产环境建议:
- 客户端设置
tcp_syn_retries=3(约15s超时) - 服务端启用SYN Cookies(
net.ipv4.tcp_syncookies=1)
- 客户端设置
- 应用程序优化:
// 设置connect超时(Python示例) import socket sock = socket.socket() sock.settimeout(8.0) # 小于系统级超时 try: sock.connect(("server", 80)) except socket.timeout: print("Connection timed out")
五、扩展知识
- SYN Flood攻击:恶意客户端伪造源IP发送大量SYN,耗尽服务端资源
- TCP Fast Open(TFO):在首次SYN包携带数据,减少握手延迟
- 连接跟踪:NAT设备需维护conntrack表,超时设置过短会导致合法连接中断
六、常见错误
- 误判为服务端故障(实际是网络路径问题)
- 未考虑中间设备(如AWS安全组默认丢弃未建立连接)
- 应用程序未设置连接超时,导致线程阻塞