Skip to content

第5章:可靠传输、UDP 与 TCP

端点与服务

UDP 保留报文边界,提供端口复用及校验等基本功能,不保证到达、顺序或不重复。应用使用 UDP,不代表应用不能自行实现可靠性。

TCP 提供有序字节流。应用一次写入的边界不会原样传给接收方:两次写入可以由一次读取取得,一次写入也可能分多次读取。应用协议必须自己定义长度字段、分隔符等消息边界。

常见 TCP 连接由源地址、源端口、目的地址、目的端口四元组区分。监听端口相同的服务器可以同时接受许多来自不同客户端的连接。

序号、确认与重传

发送方给字节编号,接收方确认已经连续收到的位置。假设收到字节区间 [1000,1500)[1000,1500),但 [1500,2000)[1500,2000) 丢失,即使随后收到 [2000,2500)[2000,2500),累计确认仍指向 1500。SACK 可以额外报告后面的已收区间,帮助发送方减少不必要重传。

确认丢失时,发送方可能重复发送已经到达的数据。接收方按序号去重,因此可靠交付并不要求网络本身从不重复。

重传超时需要适应 RTT 与抖动。太短会产生伪重传,太长会拖慢恢复。发生重传后,一个确认对应原包还是重传包可能不清楚,因此不能不加区分地用它估计 RTT。

滑动窗口与流量控制

接收窗口 rwndrwnd 告诉发送方接收缓冲还有多少能力。拥塞窗口 cwndcwnd 则由发送方根据网络状况维护。允许的在途数据受两者共同限制,通常近似为 min(rwnd,cwnd)\min(rwnd,cwnd)

接收进程读得慢会缩小接收窗口,即使网络空闲也不能无限发送。反过来,接收窗口很大,也不表示网络没有拥塞。

建立与关闭连接

握手让双方确认初始序号以及双向通信状态。TCP 的三次握手不是身份认证,不能替代 TLS。

TCP 支持半关闭:一端发送 FIN,表示该方向没有后续字节,另一方向仍可传输。TIME_WAIT 有助于处理迟到报文和最后确认的重传,并不是“服务器处理完业务”这一应用状态。

连接断开也无法直接判断业务是否执行。客户端提交扣款后超时,可能是请求没到,也可能扣款已完成、响应丢失。TCP 可靠性不能把这个业务歧义自动消掉,应用需要请求标识和持久化去重。

练习

  1. 对一个基于 TCP 的长度前缀协议,说明接收方为何必须循环读取。
  2. 接收方已收数据、确认丢失后,怎样保证应用不会读到重复字节?
  3. TCP 连接关闭是否足以证明一笔远端事务失败?

上次更新: