专题导航
网络与通信TCP 可靠传输机制与工程实践
文章目录
网络与通信

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

原理与机制

三次握手

  1. 客户端发送 SYN(同步序列号),进入 SYN-SENT 状态。
  2. 服务器收到后回复 SYN+ACK,进入 SYN-RCVD 状态。
  3. 客户端收到后发送 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 连接状态:

Terminal window
ss -tan state time-wait # 查看 TIME-WAIT 连接
ss -tan state syn-recv # 查看半连接队列
ss -s # TCP 统计摘要

工程实践与排查

嵌入式 TCP 协议栈考量:

  • 资源受限设备(如 STM32 + lwIP)的内存管理是核心问题。TCP 要求为每个连接维护发送/接收缓冲区、重传队列和状态信息。
  • 选择适当的 MSS(最大报文段大小)——太小增加头部开销,太大可能在路径 MTU 较小的链路上被分片。
  • Keep-Alive 机制在嵌入式 IoT 场景中至关重要,定期发送心跳检测死连接并释放资源。

常见问题:

  1. 大量 TIME-WAIT:通常出现在主动关闭连接的一侧。先判断是否存在不必要的短连接,再评估连接复用、长连接和系统参数;不要把 tcp_tw_reuse 当作跨平台通用修复。
  2. TCP 重传率高:检查链路质量(丢包率、延迟、抖动),可能是 WiFi 信号弱或中间路由器拥塞。
  3. 窗口过小导致低吞吐:接收方处理太慢,缓冲区不够。增大 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 不保证消息边界,应用层需要自行设计帧协议(如长度前缀或分隔符)。

官方参考资料