断点续传的核心是分块哈希与偏移校验,而非协议层重传;需用uint64_t存偏移、固定chunk大小、写后校验sha256、共用chunk_map、合理调用fsync与ftruncate,确保崩溃后仍可恢复。

断点续传的核心不是协议,是分块哈希与偏移校验
断点续传在 P2P 场景下不靠“协议层重传指令”,而靠每个 chunk 独立可验证 + 明确的 offset 和 length 描述。C++ 里最容易翻车的是把“续传”理解成 TCP 连接恢复——其实连接断了就断了,真正要保存的是已收块的元数据(比如 std::map<uint64_t bool></uint64_t> 记录哪些 chunk_id 已完整写入磁盘)。
常见错误现象:recv() 返回值被忽略,导致部分 chunk 写入不全却标记为 completed;或用 std::ofstream::write() 没检查返回字节数,文件末尾出现零填充。
- 每个 chunk 建议固定大小(如
512 * 1024),首尾对齐,避免跨块边界读写 - 接收端必须在写入磁盘后计算
SHA256并比对 peer 提供的chunk_hash,不一致就丢弃、不更新完成状态 - 偏移量必须用
uint64_t存储,32 位会溢出大文件(>4GB)
libtorrent 不适合直接嵌入,但它的 piece picker 可复用
想从零手写 P2P 协议调度逻辑?别试。libtorrent 的 piece_picker 类虽未暴露 C API,但头文件干净、无全局状态,可静态链接并提取其 add_piece / request_chunk 逻辑。硬造一套“谁该发哪块”的策略,99% 会卡在稀有度误判或请求风暴上。
使用场景:你已有 UDP 传输层(如 QUIC 或自研可靠 UDP),只需补上 BitTorrent 风格的块选择和优先级逻辑。
立即学习“C++免费学习笔记(深入)”;
- 不要复制整个 libtorrent,只摘取
src/piece_picker.*和依赖的bitfield.* - 把
piece_picker::have_piece()改成接受你自己的std::vector<bool></bool>完成状态,而非bitfield - 注意它默认按“最稀有优先”,但在内网 P2P 中可能需切到“最近请求优先”,否则小文件延迟爆炸
“P2P”不等于“去中心化”,NAT 穿透失败时 fallback 必须明确
真实网络里,两个 peer 直连成功率常低于 30%。C++ 实现中若没预设 fallback 路径,用户看到的就是“传输卡在 87%”且无日志。关键不是能不能穿,而是穿失败后是否立刻切到 relay server,以及 relay 是否共享同一套 chunk 元数据。
常见错误现象:getaddrinfo() 返回空结果却继续尝试 connect;或 relay 模式下仍用原 peer_id 请求 chunk,导致服务端拒绝(因权限绑定到原始连接)。
- STUN 检测建议用
stun-client命令行工具预验证,C++ 中调用usrsctp或pion/webrtc的 ICE candidate 生成模块更稳 - fallback 到 relay 时,必须用新 session_id 重建 chunk 请求,且 relay 服务端需支持
GET /chunk?id=xxx&offset=yyy&sig=zzz这类带签名的直链 - 所有网络路径(direct / relay / tracker HTTP)必须共用同一套
chunk_map和completed_chunks,否则续传状态分裂
磁盘 I/O 是最大隐性瓶颈,mmap + O_DIRECT 不是银弹
很多人一上来就上 mmap() + O_DIRECT,结果在 ext4 上反而慢 3 倍。Linux 下普通 write() 配合 posix_fadvise(POSIX_FADV_DONTNEED) 更稳;Windows 则必须用 CreateFileMapping() + WriteFile() 组合,FILE_FLAG_NO_BUFFERING 对小 chunk 反而有害。
性能影响:未对齐的 write() 触发 read-modify-write,SSD 寿命和吞吐双崩;而过度预分配文件(fallocate())又导致磁盘空间虚高,用户误以为“下载完了却打不开”。
- 写 chunk 前先
ftruncate()到目标 offset + length,再pwrite(),避免扩展文件锁争用 - 每写完 4–8 个 chunk 后调用一次
fsync(),别每个 chunk 都刷盘 - Windows 上禁用
FILE_ATTRIBUTE_TEMPORARY,它会让系统跳过 write cache,对续传场景极不友好
真正难的不是实现断点或 P2P,是让三者——网络可用性、磁盘一致性、内存安全——在崩溃/断电/kill -9 下依然保持 chunk 边界可恢复。多数人卡在“以为写成功了”,其实只是进了 page cache。










