【计算机网络之TCP/UDP篇】TCP三次握手与四次挥手:从原理到实战调优 1. TCP三次握手的底层原理TCP三次握手是建立可靠网络连接的基石。想象一下你打电话给朋友的过程首先你拨号SYN朋友听到铃声接起电话说喂SYN-ACK你回一句是我ACK——这就是三次握手的现实类比。具体技术实现上第一次握手时客户端会生成一个32位随机序列号ISN比如12345678并将SYN标志位置1。这个随机数很关键它能防止历史连接被错误建立。服务端收到后会回复SYNACK其中确认号是客户端序列号112345679同时携带自己的序列号如87654321。最后客户端发送ACK时确认号变为服务端序列号187654322。我在实际抓包分析时发现Linux内核默认的ISN生成算法会结合时钟和哈希值这样既保证了随机性又避免了序列号预测攻击。通过命令sysctl net.ipv4.tcp_timestamps可以查看时间戳选项这对防御SYN洪水攻击很重要。2. 为什么必须是三次握手很多新人会疑惑为什么不能两次握手。假设只有两次握手当网络延迟导致旧的SYN包突然到达服务端时服务端会误认为是新连接而直接进入ESTABLISHED状态。但客户端知道自己没发起连接导致服务端资源被白白占用。更严重的是如果攻击者伪造大量SYN包服务端的半连接队列syn_queue会被迅速打满。通过ss -lntp命令可以看到监听状态的队列情况State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:80 *:*这里的Send-Q就是半连接队列的最大长度。我曾在压测时遇到过队列溢出的情况正常请求被丢弃这时需要调整tcp_max_syn_backlog和somaxconn参数。3. 四次挥手的完整过程断开连接需要四次挥手就像挂电话时的告别你说我说完了FIN朋友回知道了ACK朋友接着说我也说完了FIN你最后确认好的再见ACK关键点在于TIME_WAIT状态。客户端发送最终ACK后会等待2MSL通常是60秒这是为了确保最后一个ACK能到达对端让网络中残留的旧报文失效通过netstat -napo可以看到TIME_WAIT连接tcp 0 0 10.0.0.1:54322 10.0.0.2:80 TIME_WAIT timewait (58.00/0)在高并发短连接场景下大量TIME_WAIT会占用端口资源。这时可以开启tcp_tw_reuse和tcp_tw_recycle注意后者在NAT环境下有问题。4. 实战调优策略半连接队列溢出当ss -s显示sockets dropped增加时说明需要调整echo 1024 /proc/sys/net/ipv4/tcp_max_syn_backlog echo 1 /proc/sys/net/ipv4/tcp_syncookiesTIME_WAIT过多对于Web服务器可以设置echo 1 /proc/sys/net/ipv4/tcp_tw_reuse echo 1 /proc/sys/net/ipv4/tcp_tw_recycle # 慎用快速重传当网络抖动时通过降低重试间隔提升体验echo 3 /proc/sys/net/ipv4/tcp_syn_retries echo 3 /proc/sys/net/ipv4/tcp_synack_retries曾经有个电商项目在促销时出现连接失败最终发现是tcp_fin_timeout默认60秒太长调整为15秒后问题解决。调优一定要结合监控数据推荐使用tcpretrans工具观察重传情况。