断点续传的核心是客户端主动告知服务端已传输偏移量并校验数据完整性。需本地保存偏移状态、服务端支持Range或自定义偏移、传输后比对哈希,且状态文件须原子化更新与强制落盘。

断点续传的核心是记录和校验已传输偏移量
断点续传不是靠“重连自动恢复”,而是靠客户端主动告诉服务端“我上次传到哪了”。C++ 中没有内置协议支持,必须自己设计状态保存机制。关键在于:每次传输前读取本地断点文件(如 transfer.state),拿到上一次写入的字节偏移;传输中每完成一块(比如 64KB),就用 fseek + ftell 或 std::ifstream::tellg() 确认当前已写位置,并原子化更新该状态文件。
用 std::ofstream 追加写入并强制刷盘避免状态丢失
状态文件必须可靠落盘,否则断电或崩溃会导致偏移错乱。不要只调用 operator 就结束:
- 用
std::ios::out | std::ios::app打开状态文件,每次只写一行纯数字(如"12345678") - 写完立刻调用
flush(),再调用fsync()(Linux/macOS)或_commit()(Windows,需) - 状态文件路径建议与目标文件同目录,命名统一为
filename.part.state,避免冲突
服务端必须支持 Range 请求头或自定义偏移参数
客户端带着偏移发起连接后,服务端不识别就毫无意义。常见错误是 HTTP 服务没启用 Accept-Ranges: bytes,或自研 TCP 协议没定义偏移字段:
- HTTP 场景:客户端发
GET /file.zip HTTP/1.1\r\nRange: bytes=1024-\r\n,服务端需解析Range头,用lseek()跳转到对应位置,再sendfile()或分块read()+send() - TCP 自定义协议:在握手包里增加
uint64_t offset字段,服务端收到后验证是否 ≤ 文件总大小,再定位读取 - 别忽略边界检查:若请求偏移超出文件长度,应返回错误码(如 HTTP 416),而非静默截断
校验环节不能只靠文件大小,必须加入哈希或分块摘要
网络丢包、磁盘静默错误、中间代理篡改都可能导致“大小对得上但内容错了”。断点续传完成后不做校验,等于白做:
立即学习“C++免费学习笔记(深入)”;
- 推荐在传输开始前,服务端预计算整个文件的
SHA-256,通过元数据接口下发给客户端 - 客户端接收完全部数据后,用
openssl/sha.h(Linux)或CryptoPP(跨平台)重新计算本地文件哈希,比对一致才删除.state文件 - 大文件可选分块哈希(如每 1MB 一个 SHA-256),边下边验,出错时只需重传对应块,但实现复杂度显著上升
最易被忽略的是状态文件的并发访问——多个进程同时传输同一文件时,fopen("x.state", "w") 会覆盖彼此。务必用 open() 配合 O_EXCL | O_CREAT 做原子创建,或用临时文件 + rename() 替换。











