摘要

  • SCTP 原来的消息寿命参数主要限制首次发送前的等待;2004 年的扩展使发送方可以在已经尝试发送后,按约定服务放弃整条消息。
  • 放弃并不填上丢失的数据。FORWARD TSN 告诉接收方哪些序号不必再等,同时处理有序消息和不完整重组留下的阻塞。
  • 发送端的期限不是接收端的保鲜期。允许继续处理、实际收到数据和应用接受内容,是三种不同的事实。

同一条消息,同时出现在三本账里

理解 SCTP 的部分可靠性,最容易出错的地方,是把一条消息只看成发送队列里的一项工作。它实际上同时出现在三本账里。

第一本是发送方的尝试与放弃账:消息是否已经开始发送,是否仍要重传,是否已按某种策略放弃。第二本是关联共享的 TSN 账:哪些传输序号已由对端真正累计确认,哪些只是发送方认定可以越过。第三本是接收方的重组与有序流账:哪些片段已经收到,哪条消息仍缺片,后续有序消息为什么还不能交给应用。

一只发送端时钟只能直接改第一本账。若消息从未取得 TSN,另外两本账甚至不必出现它;若它已有 TSN,发送方停止尝试就会在共享序号上留下义务。FORWARD TSN 处理的是这项义务如何有界地结束。它不是接收凭证,也不是删除已经到达的数据的命令。

这三本账不能压成一个“完成”字段。下面的核对不是某次事故的复盘,而是依据 SCTP 规范构造的读法:每一次状态前进,都要问是哪本账发生了什么,以及另外两本账能否据此作出同样的结论。

第一笔交叉核对:尚未编号的消息,只在本地结清

早在 2000 年的基本 SCTP 规范中,应用就可以为待发送的用户数据指定寿命。若首次发送在寿命以内还没有开始,传输层可以取消这项工作并通知上层;一旦此前已经尝试发送,原来的基本服务仍要求继续可靠传输。后来的 2007 年与 2022 年基本规范保留了这一区分。

规范提出过一个实现上的简化办法:推迟分配 TSN,并可把 TSN 分配视为发送承诺。于是,寿命在编号前耗尽时,发送方可以在第一本账上写下“未开始、已放弃”,而不在共享 TSN 账制造缺口,也不让接收方建立重组状态。这里无需用 FORWARD TSN 清理对端,因为根本没有暴露一个需要对端等待的序号。

这解释了为什么“有寿命参数”不等于“所有消息都部分可靠”。原始寿命主要决定是否开始承担工作;2004 年的扩展则允许在已经开始、甚至已经编号之后停止坚持,并为由此留下的共享状态增加继续规则。两者都谈寿命,却写入不同的账。

也因此,不能把寿命误读成 IP 的跳数限制、关联失败计时器、重传超时,或随数据传到接收方执行的时间戳。它首先是发送端判断还要不要尝试的输入。

第二笔交叉核对:102 到 106 里有一道不能跨的石坎

一条消息已有 TSN 后被放弃,发送方会在本地把它按“finally acknowledged”一类的规则从未完成发送中结清。但这个术语只属于发送方的处理账,不能抄成“对端已收到”。规范明确禁止把被放弃的字节计入相应的已确认字节信用,也不能用它们扩大拥塞窗口。若放弃也能制造发送信用,丢弃工作就会被伪装成网络完成的工作。

分片消息也按整条用户消息结算。一个片段触发放弃时,同一消息的其他 TSN 一并放弃;接收方不能被迫把残片当成完成消息。适用的拥塞与重传处理仍然存在,部分可靠性不是绕过拥塞控制的通道。

现在把第二本账摊开。RFC 3758 的发送方示例从实际累计确认 102 开始:103、104 已被放弃;105 未获确认,而且仍是可靠、未放弃的石块;106 已得到确认。发送方另存的 Advanced.Peer.Ack.Point 可以沿连续的 abandoned TSN 从 102 前进到 104,却不能因为 106 已确认就跨过 105。

这里必须同时保留两个位置:actual cumulative acknowledgment 仍是对端真实报告的 102;Advanced.Peer.Ack.Point 是发送方依放弃规则计算出的 104。后者不是伪造的累计确认,也不是对端收件状态的镜像。只有在这个 advanced point 超过实际累计确认时,发送方才有理由发出 FORWARD TSN,告诉对端哪一段等待义务可以结束。

这道 105 的石坎是部分可靠性没有破坏可靠消息的证据。即使后面的 106 已成功,未确认且未放弃的 105 仍不能被某条更新消息、某个更高业务优先级或发送方想尽快清空队列的愿望越过。共享继续规则只覆盖已经被合法放弃的连续边界。

第三笔交叉核对:接收端的 102、103、104、105、106、107

接收方示例是另一组排列,不能与发送方示例拼成一条抓包记录。其累计点起初也是 102;103 缺失;104 和 105 已经收到;106 缺失;107 已经收到。收到指向 103 的 FORWARD TSN 后,接收方先把累计点从 102 移到 103,再凭手中真实存在的 104、105 前进到 105。

这里的 105 不是整段都被“视同送达”。103 是被正式允许缺席,104 与 105 是实际持有的数据。到达 106 时,第三本账再次停住:106 既未收到,也没有获准越过。已经收到的 107 不能替它填坑。发送端示例中的可靠石块是 105,接收端示例中的阻挡点是 106;两例共同说明,后方的成功不能取消前方仍有效的可靠义务。

旧的或相同位置的 FORWARD TSN 不会让接收方累计点倒退。它仍可能促使接收方回送 SACK,因为此前的确认也许丢失。FORWARD TSN 本身同样可能丢失,发送方必须保持相关重传定时处理,并在定时器到期时重新审视前移条件。一次发出控制消息,不足以证明第三本账已经更新。

接收方前移后,迟到的、已被越过的 DATA 按该规则作为重复数据丢弃。这只规定以后如何处理迟到副本,不会抹去先前已经交给应用的内容,更不能证明那份内容从未抵达。发送端的 lifetime 因而不是 receiver deadline,也不是 recall。

TSN 账前进以后,重组账和有序账还要分别收尾

TSN 累计点只回答序号处理到了哪里,并不自动完成消息重组。若一条消息仍缺少位于新累计点以下的片段,它已经不可能按原要求完整重组,接收方必须移除相关不完整状态;若 partial delivery 已经开始,上层还应获知该消息不会完成。把残片从内存中清走,不等于撤回已经部分交付的字节。

有序流还有另一种等待:后续消息可能完整到达,却因前一条有序消息缺失而不能交付。FORWARD TSN 因此可携带相应的流与消息序号信息,释放被 abandoned ordered data 卡住的后续内容。无序消息不能被写进这些有序流条目;部分可靠与有序/无序是两个独立选择。

应用若想从流序号辨认业务缺口,也只能在相关流全部按有序方式使用时依赖该办法。不能从无序通信中推导出同样的缺口证据。三本账的意义至此更加清楚:共享 TSN 账允许关联前进,重组账决定一条消息能否完成,有序流账决定完成的后续消息何时可交付。

先核对这次关联是否允许改共享账

发送方不能因为本机代码支持部分可靠性,就单方面写第二、第三本账。RFC 3758 要求在 INIT/INIT ACK 中协商支持。一端即使具备能力,只要这次没有宣告,就必须按未启用处理;对端缺乏支持时,不得发送 FORWARD TSN。上层可以据此放弃建立关联,或接受在没有部分可靠性的条件下继续。

这项协商只建立共同的继续语法,不要求接收方知道发送方为何放弃。发送策略可以是时间、重传次数或合规的其他政策;接收方处理的仍是同一条有边界的跳过通知。能力、宣告、实际启用和某条消息最终被放弃,是四种证据,不能由产品功能清单互相替代。

定时策略本身也不需要在到期的精确瞬间为每条消息触发一次中断。规范要求在 TSN 分配前,以及已经编号的数据发送或重传前检查;也允许在其他方便时机检查。应用把消息交给 SCTP 后不能再改变其寿命。已经发出的副本可能在放弃判断之后、跳过通知之前到达,这是规范语义允许的假设顺序,并非观察到的事故。

由于接收方无需知道发送策略,这个 lifetime 也没有建立同步的远端保鲜期。若应用必须拒绝旧版本,它需要在接收或执行环节使用自己的版本、时间或状态条件。

后来的政策,只改第一本账为何结清

资料性的 SCTP 套接字 API 用策略选择器和值区分可靠模式与按寿命的部分可靠模式,寿命值以毫秒表达。它不是所有平台常量、ABI 或默认值一致的证据。后来的扩展又增加按 DATA 块重传次数限制和按发送缓冲优先级取舍的政策,但没有改写接收方理解 FORWARD TSN 的共同办法。

重传次数政策中,构成消息的任一 DATA 块若将超过允许次数,整条消息被放弃;快速重传和定时重传都计数。上限为零表示在第一次需要重传时放弃,不是“绝不首次发送”,更不是成功送达一次的证明。路径和关联失败阈值仍有自己的职责。

优先级政策是在新消息需要发送缓冲空间时,从同一关联的较低优先级候选中作本地取舍。可靠消息高于这类候选。它不是网络转发优先级,也不给发送方支配对端调度的权力。资料性计数器还区分整条消息在任何部分发送前被放弃,或至少发出一个片段后才被放弃;它们统计用户消息,不是碎片,也不能在没有实现证据时假定每个平台都提供。

WebRTC 数据通道后来要求其栈支持按时间和有限重传的部分可靠性。这里有序/无序与完全/部分可靠仍是不同维度;一个数据通道使用一对相反方向的 SCTP 流。其层次是 SCTP over DTLS over ICE/UDP,DTLS 保护该栈中的整个 SCTP 包。这个标准要求既不是当前浏览器部署统计,也不能外推成每条原生 SCTP 流都具有固定政策。

从早期 lifetime 到后来政策,真正稳定的不是某个计时值,而是三本账的权限边界:发送方可以决定还要不要努力;共享序号只能按协商过的连续放弃边界前移;接收方仍须依真实到达、重组和有序状态决定能交付什么。部分可靠性允许消息缺席,却没有把缺席改写成送达。

资料依据

  • RFC 2960:基本发送接口中的寿命与首次尝试。
  • RFC 3758:部分可靠性、FORWARD TSN、双方序号处理和按寿命服务。
  • RFC 4960:后续基本规范中的寿命语义。
  • RFC 6458:资料性套接字接口中的策略和值。
  • RFC 7496:重传次数、缓冲区优先级和弃置统计。
  • RFC 8831:WebRTC 数据通道要求与协议层次。
  • RFC 9260:2022 年基本 SCTP 规范的接口边界。