Skip to content

两条流分别推进,一份信用共同结算 ​

这个任务的终点是两份可逐行解释的状态:每条流究竟交付到了哪里,连接总账究竟记了多少。独立交付不等于独占资源;取消也不等于从历史中抹去全部数据。

核心两站为多路复用流的独立重组→多流信用与最终长度结算。按需先补R9前缀证明、TCP字节序号和接收许可;再进阶读应用背压、业务结果未知与认证记录层。这是阅读安排,不把相邻阅读站自动当作概念依赖。

下载Python检查器。Python 3.10或更新版本,仅用标准库,无网络连接或额外安装:

text
python foundations-multiplexed-stream-checker.py
python foundations-multiplexed-stream-checker.py --compact
python -O foundations-multiplexed-stream-checker.py --compact

完整模式输出每次接收的包身份、帧增量、已见包号、各流覆盖、前沿、最终长度和额度。检查用显式异常,优化模式不会关掉测试。所有字节和连接名都是公开教学数据。

入口自测 ​

  1. [2,4)到达而[0,2)缺失,连续交付前沿是多少?答案是0,最高已见末端却是4
  2. 同一位置的字节重新封装到新包里,包身份和内容身份哪个改变?答案是包号改变,流号、方向和偏移不变
  3. 接收应用不再需要某条流,能否立即认定最终长度等于当前缓存大小?答案是否,因为还有缺口和在途数据,必须获知发送侧最终长度

若第一题不熟,先在R9纸面格子上演练;能分清这三个问题即可进入实验。

1. 固定模型,再算独立前沿 ​

固定一个已经建立且认证的连接、c2s方向和一个应用数据包序号空间。只有已经准入的流0、4,每流课堂数组容量64。它们是客户端发起的双向流,本任务只操作c2s半部;反方向另有状态。偏移与包号不绕回,发送者不复用包号且同流同偏移内容不变。

输入已经通过认证与外层格式检查,网络可以丢失、乱序或复制包。本实验不实现密码算法、握手、拥塞控制、包丢失判定、重传计时器、建流或迁移。所列“重传”是指定的新包携带相同内容;这避免把演示接收逻辑误称为完整可靠传输实现。

流0发送abcd,流4发送XY。按如下事件分别写下Seen、覆盖、r_0、r_4,以及本次新增交付:

  • 包10含s0:[0,2)=ab,发送后丢失
  • 包11含s4:[0,2)=XY,到达
  • 包12含s0:[2,4)=cd,到达
  • 包13含s0:[0,2)=ab,到达
  • 包14又含s0:[0,2)=ab,到达

答案与理由 ​

到达包 Seen s0覆盖 s4覆盖 (r_0,r_4) 新交付
11 空 [0,2) (0,2) s4:XY
12 [2,4) [0,2) (0,2) 无
13 [0,4) [0,2) (4,2) s0:abcd
14 [0,4) [0,2) (4,2) 无

包10未到,当然不在Seen中。包14是新包,包级去重不能跳过它;流偏移检查让它不再输出ab。再复制包11时才命中Seen。若此前丢失的包10只是严重迟到,仍是未见包号,不能用“比最大包号小”拒绝它;处理后覆盖与输出都不变。

复算四次有效到达

证明不能只看最终字符串:每一步都应保持每流已填位置等于原串同位置、输出恰为[0,r_i)前缀、r_i单调;操作s0不得修改s4的字节数组。原子检查在暂存状态上依次处理本包所有帧,通过后才提交;错误包的后帧不能让早先暂存输出泄漏给应用。

2. 用相同载荷构造TCP上的HTTP/2对照 ​

假定HTTP/2连接与流1、3的HEADERS均已经处理。将逻辑流0映射到HTTP/2流1,逻辑流4映射到HTTP/2流3;HTTP/2的流0不能装DATA。

构造三个无填充DATA帧,顺序为(s1,ab)、(s3,XY)、(s1,cd)。每帧头9字节,载荷2字节,完整编码为:

text
00 00 02 00 00 00 00 00 01 61 62
00 00 02 00 00 00 00 00 03 58 59
00 00 02 00 00 00 00 00 01 63 64

头前三字节是载荷长度2,类型0是DATA,标志0无填充/无END_STREAM,末四字节为流号。这里从已处理前缀之后重新以0编号TCP子序列,不是重新建立TCP连接。

让[0,11)丢失,随后[11,22)、[22,33)、重发[0,11)、重复[0,11)依次到达。请写出TCP前沿和HTTP/2逻辑输出。

答案与理由 ​

前沿依次为0、0、33、33。前两次HTTP/2解析器没有新的连续输入,两条逻辑流都没有本实验中的新增输出。第三次一次拿到33字节,解析出ab、XY、cd,按流分别得到abcd与XY;第四次不产生新增字节。

多流重组里XY在包11到达时已可交付;单TCP对照里,XY的帧字节虽在内核暂存,仍无法越过共同前缀缺口。这只证明具体等待关系的区别。真实HTTP/3还有帧语义与QPACK依赖,本检查器没有验证HTTP/3请求完整性。

3. 另开一份4+3信用账本 ​

本节是独立输入,不沿用XY的长度2。给两流L_0=L_4=6、连接C=8。先收到s0:[2,4)=cd及s4:[0,3)=XYZ,所以H_0=4、H_4=3、T=7;s0实际只缓存2字节,仍计到末端4。这里的额度更新是“接收方已授予且发送方已收到通告”的同步事件;MAX通告实际沿反方向传递,实验省略控制传播延迟,不混用本端发送与接收预算。

依次重复s0:[2,4),提高MAX_DATA到10,收到s0的RESET(final_size=6),再收到迟到的s0:[4,6)=ef,最后收到旧MAX_DATA(8)与旧MAX_STREAM_DATA(s4,3)。填写每步H、T、余额和交付。

答案与理由 ​

重复区间增量0;提高连接上限后T仍为7,余额3;RESET把s0补记到6,增量2,T=9,余额1。迟到ef落在已知最终范围内,不再交付也不再收费。较小额度忽略,C仍10、L_4仍6。s0从未有连续前缀,所以整个分支没有交付任何s0字节;重置不会制造缺失ab或正常EOF。

独立信用账本

现在每次都从原始4+3快照新建一条分支,判断:

改动 必须指出的失败依据
C仍8就RESET s0,f=6 总账将为9,超过连接许可
RESET s0,f=3 小于先前H_0=4,最终长度矛盾
C=20但s0末端变7 超过单流许可6
C=8,一包让两流末端各加1 每流都合法,总账9却超8
已知FIN最终长度4,再RESET为6 不能改变已确定的最终长度

检查器分别报告FlowControlError或FinalSizeError,本次暂存账本不提交,连接进入FAILED并拒绝后续接收。错误分支各自使用新实例;异常不是“拒收这一包后继续同一连接”的隐含恢复协议。

4. FIN、停读和两个方向 ​

正常分支先接收s0:[2,4)=cd且FIN=true。此时F_0=4、H_0=4、r_0=0,不能报告正常完成。补入ab才使r_0=4并完成;本教学策略在正常完成后收到一致的RESET(4)不撤回完成。空流的offset0、空数据FIN则立即完成,计费0。QUIC的FIN不额外占字节偏移。

停读分支先收到cd,随后stop_reading(s0),表示本地不再交付并请求发送STOP_SENDING。此刻F仍未知,T不变。迟到e占[4,5),H_0增到5,必须继续检查额度;RESET(6)最终结算到6。后来即使abcdef与一致FIN一并迟到,也不会重新交付已重置半部。

对同一双向流,独立的s2c接收器仍可收到OK并正常完成。c2s的RESET、STOP与账本不删掉反方向。STOP_SENDING请求对端停止那个发送半部;RESET_STREAM是本端终结自己发送半部的报告,两者的发送者角色不同。真实规范的完整发送状态和控制帧重传在本实验之外。

迁移题:改结构,不只换数字 ​

迁移一:一个包里有两个流 ​

包20同时带s0的ab与s4的X,整包丢失。包21带s0的cd与s4的Y,到达;包22仅带重发的s4:X;包23才带s0:ab。依次算前沿。

答案:(0,0)→(0,2)→(4,2)。一次丢包可以影响两流,但s4补齐后无须继续等s0。若实现只给整连接一个“最早缺失流号”,第二步会错误阻塞s4。

迁移二:取消时只剩几个孤立字节 ​

流0只到[2,4),然后RESET的最终长度为6。能否用缓存2作为连接贡献?能否用原最高末端4?

答案:两者都不够。应按6结算;4是RESET到达前的最低已知贡献,2只描述缓存物理数量。若先报STOP且尚未得到最终长度,也不能提前认定4就是最终值。

迁移三:同包中先合法、后非法 ​

新包先放s4:XY,再放与已存s0位置1冲突的X;或新包先放s0:ab,再放同包位置1的X。在这份原子接口里会发生什么?

答案:ContentConflict,整包暂存写入与暂存输出均不提交,连接FAILED。第二种情况说明冲突比较必须包含本包之前的暂存帧;只与包到达前的数组比较会漏检。此前其他成功包已交付的数据不会被回滚。

迁移四:让一个消费者永远停住 ​

两流重组都没有缺口,就能保证另一流持续发送吗?

答案:不能。若慢流占满连接信用,另一流虽有自身额度仍不能扩大末端;共享拥塞预算、调度和CPU也可能拖慢它。可在已授权资源范围内提高连接信用并限制慢流,但不会凭空获得内存或消费能力。单流许可、连接许可与应用队列容量必须分别解释。

迁移五:换CID或重开流就能安全重做业务吗 ​

答案:不能。CID用于连接分派,一个连接可有多个CID;它不是认证或业务操作ID。流和包的去重不跨新连接建立持久业务去重,ACK也不是业务提交证据。业务请求的未知结果仍回到既有R9终点的结果判定,认证、nonce与重启仍回到安全会话终点。本组没有改写这两个合同。

检查覆盖与完成标准 ​

检查器实际枚举三种片段组成的243条长度5事件串,再补发三种片段;每步验证前缀并穿插同包号副本。另检查24种重叠重分段排列,以及1050个合法初态上的最终长度算术分支。独立手写轨迹覆盖上述TCP对照、FIN先到、空FIN、停读、反方向、同/新包号重复、迟到原包、一包多流、两层错误、同包冲突、最终长度矛盾、错误上下文、非ASCII字节与偏移越界。

会完成本任务意味着能从输入推导每行状态,解释每个拒绝究竟来自哪道门,并在改变分包或取消时重新保持同一不变量。测试范围不是规范一致性认证,更不是网络性能结论。

保存Seen全集、定长数组、已结束流元数据及输出历史让有限轨迹容易审计,却不适合无限运行;每包deepcopy还增加演示成本。真实实现需要接收历史回收、gap结构、资源准入、密码保护与恢复策略的完整合同。本检查器没有真实I/O,没有模拟控制消息ACK或业务执行,也不证明永久丢包时能完成。

参考资料 ​

  • RFC 9000,§§2–4、5.1–5.2、12.3、13.3、19.4–19.10:流、信用、最终长度、身份和重发信息。本文数值与原子模型是独立构造
  • RFC 9113,§§1–2、4.1、5:HTTP/2帧结构与TCP传输边界
  • RFC 9114,§2、§§4.1–4.2.1:HTTP/3流映射、终结与压缩依赖;仅作边界对照