Skip to content

消息编码 ​

本文记录当前 Rust SDK 实际发送和接收的文件协议。网络无关的编码定义在 q2q-core::peer_wire,握手签名输入在 q2q-core::peer_auth;SDK 通过 q2q::protocol::peer 重导出 Peer 编码。

连接与通道配置见 传输层,消息与持久化之间的顺序见 调度。本页描述当前实现,设计稿中的 pause/resume 和磁力链 info 获取尚未接入。

身份确认 ​

身份确认先于 bitfield,使用可靠控制通道上的 JSON 文本消息,不套文件协议 envelope:

json
{"type":"identity_hello","v":1,"nonce":"<base64: 32 bytes>"}
{"type":"identity_proof","v":1,"signature":"<base64: 64 bytes>"}

双方先交换随机 nonce,再验证绑定当前连接与双方 DTLS 指纹的 Ed25519 签名。消息最多 512 字节,总限时 10 秒;业务消息不能代替身份消息。

控制消息 ​

每个控制消息占一个文本 DataChannel 消息,最多 16 KiB:

json
{"v":1,"message":{"type":"request","block_index":0,"count":1}}

当前版本为 1,未知版本、类型和控制 envelope/message 中的未知字段会被拒绝。

type字段当前语义
bitfieldbitsbase64 位图,按 block 标记已验证内容
haveblock_index当前块已通过校验并持久化
requestblock_index, count请求单块,当前 count 必须为 1
request_proofblock_index, count重请求当前块的 Merkle 证明
proofblock_index, count, proof单块证明,走可靠通道
upload_waitblock_index, retry_after上传端等待限速预算,暂缓重试 1–30,000 毫秒
piece_nackblock_index, piece_offset, length成对的缺失字节区间数组
block_doneblock_index接收者已完成,上传者可以释放该块重传缓冲
cancelblock_index, count当前 SDK 以两字段均为 0 表示结束当前文件会话
rejectblock_index, count, retry_after拒绝请求,retry_after 单位毫秒;当前调度器淘汰该连接

位图的 block 0 对应首字节最高位,未使用的末尾低位必须为 0;长度必须恰好覆盖 block 数,最多 65,536 块。允许部分来源位图,只请求该连接宣告可用的块;Have 更新连接位图并唤醒选块,越界索引使连接失败。Track 只保存部分/完整状态,不保存块位图。

proof 使用 q2q_core::merkle::Proof 的 JSON 表示。单块证明的 count 为 1、nodes 最多 64 个、leaf_hashes 最多 1 个;是否有效仍需按块字节、索引、文件块数和可信根验证。Seed 版本与文件协议 envelope 版本是不同的版本字段。

二进制 piece ​

每个 piece 占一个二进制 DataChannel 消息,不额外附加长度前缀:

字节偏移长度内容
04ASCII 魔数 Q2QP
41版本 1
58block_index,u64 大端
134piece_offset,u32 大端
171–1024数据字节

piece_offset 是块内字节偏移,必须按 1024 对齐,不是 piece 序号。最后一个 piece 可以不足 1024 字节;越界、错误块索引、冲突的重复 piece 或文本数据帧都会使当前接收失败。已在本连接完成的块的迟到 piece/proof 会被忽略。

补片与结束 ​

块接收有 20 秒进展截止时间,只有新有效 piece 或当前块的 upload_wait 能刷新。500 毫秒无新有效 piece 时触发检查,两次新 piece 之间最多三轮重试,新有效 piece 会重置重试次数;证明缺失时发送 request_proof,数据缺失时发送 piece_nack。每条 nack 最多 64 个区间,两个数组长度相同,区间需按序、不重叠、对齐且不越界。可靠 proof 与不可靠 piece 的到达顺序可能不同。

上传端只保留一个在途块,收到 BlockDone 才释放重传缓冲。接收端所有所需块完成后发送 cancel { block_index: 0, count: 0 },上传端回显,接收端收到确认再关闭连接;上传端等待连接关闭。结束握手也用于只补齐部分块的会话。

这里的 cancel 是当前 SDK 的会话结束约定,不代表已经实现任意块区间的暂停/恢复协议。文件传输的控制消息等待使用 30 秒 idle 限制;应用取消和 VOD 紧急块回退也可能提前关闭连接。

upload_wait 只在上传端等待共享限速预算时发送,SDK 每秒刷新一次 2000 毫秒的提示。接收端暂缓缺片检查,并把进展截止时间刷新到至少 20 秒后(提示时长更长则使用该时长);之后到达的 piece 不会缩短已提示的重试窗口。非法时长或无关块索引使连接失败;已完成块的迟到提示被忽略,包括会话结束期间。持续发送有效提示的节点可以延长传输,应用可取消,VOD 读取仍受配置超时限制。控制 envelope 版本仍为 1,旧 SDK 会拒绝新增消息,限速上传需要两端都支持此扩展。

设计稿,随时会改