TCP 可靠传输机制与工程实践
从三次握手、确认重传、流量控制到拥塞控制,系统理解 TCP 如何在不稳定的 IP 网络之上构建可靠的数据流。
本文解决什么问题
理解 TCP 如何在不可靠的 IP 层之上提供可靠的字节流传输服务——包括连接建立与断开、序列号与确认机制、重传策略、滑动窗口流量控制和拥塞控制算法。掌握 TCP 的核心状态机、关键定时器和常见工程排查手段。适合嵌入式网络应用或 IoT 设备开发者。
核心概念与直觉
TCP 的可靠性来自四个核心机制:
- 确认与重传:每发送一段数据,对方必须确认收到;超时未确认则重发。
- 序列号:每个字节都有编号,接收方按序重组,乱序或丢失能被检测到。
- 流量控制:接收方告知发送方”我还能接收多少数据”(窗口字段),防止发送太快淹没慢速接收方。
- 拥塞控制:发送方探测网络能承受的速率,在丢包时主动降速,避免压垮中间路由器。
关键结构或工作流程
sequenceDiagram
participant C as 客户端
participant S as 服务器
Note over C,S: 三次握手
C->>S: SYN, seq=x
S-->>C: SYN+ACK, seq=y, ack=x+1
C->>S: ACK, seq=x+1, ack=y+1
Note over C,S: 数据传输
C->>S: PSH+ACK, seq=x+1, ack=y+1, len=100
S-->>C: ACK, seq=y+1, ack=x+101
Note over C,S: 四次挥手
C->>S: FIN, seq=u
S-->>C: ACK, seq=v, ack=u+1
S->>C: FIN, seq=w
C-->>S: ACK, seq=u+1, ack=w+1原理与机制
三次握手
- 客户端发送 SYN(同步序列号),进入 SYN-SENT 状态。
- 服务器收到后回复 SYN+ACK,进入 SYN-RCVD 状态。
- 客户端收到后发送 ACK,进入 ESTABLISHED 状态。服务器收到此 ACK 后也进入 ESTABLISHED。
为什么是三次而不是两次?因为网络可能延迟重复旧的 SYN 报文。三次握手让客户端可以明确拒绝旧的 SYN+ACK(不发送最后的 ACK)。
四次挥手
因为 TCP 是全双工的,每个方向需要独立关闭。主动关闭方发送 FIN → 被动方 ACK(半关闭) → 被动方处理完剩余数据后发送 FIN → 主动方 ACK → 主动方进入 TIME-WAIT(等待 2MSL 确保最后的 ACK 被收到)。
滑动窗口与流量控制
接收方在 TCP 头部”窗口大小”字段告知发送方自己剩余缓冲区空间。发送方确保”已发送未确认”的数据量不超过窗口大小。窗口为 0 时发送方停止发送,并定期发送窗口探测报文。
拥塞控制
以经典 TCP Reno 的教学模型为例,常见的四个机制是:
- 慢启动:cwnd 从协议栈选择的较小初始窗口开始,通常按每个 RTT 近似指数增长,直到达到 ssthresh;初始窗口并非跨实现固定为 1 MSS。
- 拥塞避免:超过 ssthresh 后,每个 RTT cwnd 增加 1 MSS(线性增长)。
- 快速重传:收到 3 个重复 ACK 立即重传,不等超时。
- 快速恢复:快速重传后降低发送窗口,但避免像超时那样完全回到初始阶段;具体窗口更新规则取决于拥塞控制算法和实现。
示例代码或操作流程
Wireshark 过滤器用于排查 TCP 问题:
tcp.stream eq 0 # 查看特定连接tcp.analysis.retransmission # 过滤重传报文tcp.window_size == 0 # 过滤零窗口通告tcp.flags.reset == 1 # 过滤 RST 报文用 ss 命令查看 Linux 系统 TCP 连接状态:
ss -tan state time-wait # 查看 TIME-WAIT 连接ss -tan state syn-recv # 查看半连接队列ss -s # TCP 统计摘要工程实践与排查
嵌入式 TCP 协议栈考量:
- 资源受限设备(如 STM32 + lwIP)的内存管理是核心问题。TCP 要求为每个连接维护发送/接收缓冲区、重传队列和状态信息。
- 选择适当的 MSS(最大报文段大小)——太小增加头部开销,太大可能在路径 MTU 较小的链路上被分片。
- Keep-Alive 机制在嵌入式 IoT 场景中至关重要,定期发送心跳检测死连接并释放资源。
常见问题:
- 大量 TIME-WAIT:通常出现在主动关闭连接的一侧。先判断是否存在不必要的短连接,再评估连接复用、长连接和系统参数;不要把
tcp_tw_reuse当作跨平台通用修复。 - TCP 重传率高:检查链路质量(丢包率、延迟、抖动),可能是 WiFi 信号弱或中间路由器拥塞。
- 窗口过小导致低吞吐:接收方处理太慢,缓冲区不够。增大 socket buffer 或优化应用读取逻辑。
常见误区
- 误区:“TCP 保证数据一定能送达” → TCP 尽最大努力送达,如果链路中断超过重传次数上限,协议栈会放弃并返回错误。应用层仍需处理连接断开。
- 误区:“发送方调用 write() 后数据立即被对方收到” → TCP 是字节流协议,Nagle 算法可能延迟小包发送。没有消息边界。
- 误区:“TIME-WAIT 是无用的等待” → 它确保最后的 ACK 被对方收到、让网络中的延迟重复报文自然消失。
深入理解
SYN Flood 攻击与 SYN Cookie:攻击者发送大量 SYN 但不完成握手,占满服务器的半连接队列。SYN Cookie 是一种防御机制——服务器不分配资源,而是将连接信息编码在 ISN 中。
TCP Fast Open (TFO):允许客户端在 SYN 报文中携带数据,服务器可以立即处理而无需等待三次握手完成。适合 HTTP 请求等短连接场景。
小结
- TCP 通过序列号+确认+重传在不可靠 IP 上提供可靠字节流,三次握手建立连接,四次挥手关闭。
- 滑动窗口实现流量控制,拥塞控制(慢启动/拥塞避免/快速重传/快速恢复)适配不同网络状态。
- 嵌入式 TCP 协议栈开发的核心挑战是内存管理和吞吐优化。
- Wireshark TCP 分析、系统连接状态监控是排查传输问题的基本工具。
- TCP 不保证消息边界,应用层需要自行设计帧协议(如长度前缀或分隔符)。