两条流分别推进,一份信用共同结算
这个任务的终点是两份可逐行解释的状态:每条流究竟交付到了哪里,连接总账究竟记了多少。独立交付不等于独占资源;取消也不等于从历史中抹去全部数据。
核心两站为多路复用流的独立重组→多流信用与最终长度结算。按需先补R9前缀证明、TCP字节序号和接收许可;再进阶读应用背压、业务结果未知与认证记录层。这是阅读安排,不把相邻阅读站自动当作概念依赖。
下载Python检查器。Python 3.10或更新版本,仅用标准库,无网络连接或额外安装:
python foundations-multiplexed-stream-checker.py
python foundations-multiplexed-stream-checker.py --compact
python -O foundations-multiplexed-stream-checker.py --compact
完整模式输出每次接收的包身份、帧增量、已见包号、各流覆盖、前沿、最终长度和额度。检查用显式异常,优化模式不会关掉测试。所有字节和连接名都是公开教学数据。
入口自测
- [2,4)到达而[0,2)缺失,连续交付前沿是多少?答案是0,最高已见末端却是4
- 同一位置的字节重新封装到新包里,包身份和内容身份哪个改变?答案是包号改变,流号、方向和偏移不变
- 接收应用不再需要某条流,能否立即认定最终长度等于当前缓存大小?答案是否,因为还有缺口和在途数据,必须获知发送侧最终长度
若第一题不熟,先在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字节,完整编码为:
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或业务执行,也不证明永久丢包时能完成。