摘要

  • QUIC DATAGRAM 不可靠地承载一个应用数据报,并保留其消息边界,但不会重传,也不保证不同 DATAGRAM 消息之间的顺序。
  • max_datagram_frame_size 是单向接收支持和大小信号,不是容量、送达或处理承诺。
  • 数据包 ACK 证明传输层处理,不能替代应用层确认或业务完成证明。

最容易发生的误判,是把本地提交成功写成远端送达。QUIC DATAGRAM 的设计正好限制了这种推断。一个 frame 可以携带一个应用数据报,接收方可以知道这段数据的边界;但扩展不会创建流偏移、按字节有序交付,也不会在检测到丢失后重传该 frame。不同 DATAGRAM 消息之间同样没有顺序保证。消息仍是一条消息,可靠性承诺却没有随之出现。

还必须区分 QUIC DATAGRAM frame 与承载 QUIC 数据包的 UDP 数据报。frame 位于 QUIC 数据包内部,数据包又可能位于 UDP 数据报内部。三者是不同层次的对象。看见外层 UDP 数据报、看见 QUIC 数据包,或看见数据包被 ACK,都不能直接证明应用消息已经被对端应用消费。

max_datagram_frame_size 按方向协商。默认值为零;非零值表示该端点愿意在相应方向接收符合条件的 DATAGRAM frame,并受握手及适用的 0-RTT 保留状态规则约束。发送方不得超过对端公布的值。这个参数不证明对端拥有可用的应用内存,也不证明它会交付、保留或处理数据。实际可用大小还可能受 max_udp_payload_size 和路径 MTU 限制。该扩展不能分片 DATAGRAM frame,因此应用协议必须处理更小的有效上限。

DATAGRAM frame 属于整个 QUIC 连接,没有 QUIC stream ID。逻辑流标识、数据含义、过期策略、去重键、必要时的顺序规则,以及什么算完成,都由应用协议负责。传输层无法从 frame 本身推断业务消息身份,也无法判断两个数据报是不是同一操作的重复尝试。

应用提交后,QUIC 会生成新的 DATAGRAM frame,并在允许时尽快把它放入可用数据包,同时受拥塞控制和 pacing 约束。如果拥塞控制尚未允许发送,实现必须保留该 frame 等待发送,或在发送前丢弃;应用设置的过期时间也可能导致发送前丢弃。因此 API 返回成功只能按该 API 的实际契约解释,RFC 9221 并没有把它定义为线路发送、对端接收或应用完成回执。

接收端只有在能够处理 frame 并把内容保存在内存中时,才应立即交给应用。DATAGRAM 没有显式流控,也不计入通常的流或连接数据限制。没有出现流控阻塞,不代表接收端有处理能力。接收端可以丢弃自己无法处理的数据。

DATAGRAM frame 会触发 ACK,即使丢失检测后不会重传它。承载该 frame 的数据包可能被延迟确认;发送方也可以发送探测数据包来更快获得 ACK。重新排序还可能推翻早先的临时丢失判断。ACK 证明接收方传输层处理了该 frame 所在的数据包,不证明接收方应用处理成功,更不证明持久化或业务完成。

建议把证据分成独立记录:应用消息或流标识、本地受理和 API 结果、过期或丢弃策略、单向协商支持和有效大小、拥塞或 pacing 延迟、发送前丢弃、数据包编号和编号空间、ACK 或丢失观察及其因重排产生的反转、接收方传输层处理、应用处理以及持久化或业务完成。这样才能解释数据究竟在哪里停止。