断点续传的核心判断依据是服务端返回的已接收字节偏移量。客户端每次上传前需通过head或/status接口查询服务端当前文件大小,据此确定起始offset;c++中须以binary模式用seekg()精准跳转,并校验fail();多线程下各分片独立携带start_offset和length,由服务端统一校验写入;遇416错误应先确认服务端实际长度,再决定是否重传。

断点续传的核心判断依据是什么
断点续传不是靠“记住上次传到哪”,而是靠服务端和客户端共同维护一个已接收的字节偏移量。客户端每次上传前先向服务端查询该文件的当前大小,再从这个位置开始发送剩余数据。关键在于:HTTP Range 请求头或自定义协议中携带 offset 字段,服务端据此决定是否接受分片、是否覆盖、是否校验一致性。
常见错误是只在客户端记录本地文件写入位置,却没和服务端状态同步——一旦服务端重启或清理临时文件,续传就失效。
- 必须通过一次轻量级探针请求(如
HEAD或专用/status?file=xxx接口)获取服务端已存长度 - 若服务端返回
Content-Range: bytes 0-1023/2048,说明已收前 1024 字节,下次应从偏移1024开始 - 若服务端不支持断点(如返回
404或无Content-Range),则需重置为从头上传
用 C++ 的 fstream 跳过已传部分
C++ 标准库本身不处理网络续传,但本地文件读取阶段需要精准跳过已上传字节。别用 seekg(n, ios::beg) 简单跳转——二进制文件中换行符、编码、BOM 都可能导致偏移错位。
正确做法是直接按字节偏移定位,且确保 fstream 以 ios::binary 模式打开:
std::ifstream file("large.bin", std::ios::binary);
if (file.is_open()) {
file.seekg(offset); // offset 是服务端返回的已收字节数
// 后续用 file.read(buffer, size) 读取剩余内容
}
-
seekg()在二进制模式下才是精确字节跳转;文本模式会触发换行转换,破坏偏移对齐 - 调用
seekg()后务必检查file.fail(),尤其当offset超出文件实际大小时会静默失败 - 不要依赖
file.tellg()反查当前位置来“验证”跳转结果——某些流实现(如 Windows 下带缓冲的文件)可能返回未刷新的缓存位置
如何避免多线程上传时的 offset 冲突
如果多个线程并发上传同一文件的不同分片,offset 不是线程安全的共享变量。典型错误是让每个线程自己计算起始位置,结果因文件被其他线程截断或重命名导致偏移错乱。
真正可行的方案是:所有分片上传请求都携带独立的 start_offset 和 length,由服务端统一校验并原子写入。C++ 客户端只需保证每个请求参数准确,不维护全局 offset 状态:
- 分片大小建议固定(如
1024 * 1024字节),最后一个分片按余量计算length - 每个分片请求附带
Content-Range: bytes 1024-2047/10000,服务端据此定位写入位置 - 本地不缓存 offset,每次发请求前重新查服务端状态——看似低效,实为唯一可靠方式
服务端返回 416 Requested Range Not Satisfiable 怎么办
这个错误意味着客户端传的 Range 头超出服务端当前文件长度,比如服务端只有 500 字节,你却请求 bytes=1000-1999。C++ 客户端不能忽略它直接重试,而应主动降级处理:
先尝试 HEAD 请求确认服务端当前长度;若发现服务端长度小于预期,则说明中间有清理或异常中断,必须从头上传或人工干预。
- 收到
416后立即停止后续分片,避免浪费带宽 - 不要自动 fallback 到
0-全量上传——可能覆盖服务端已有有效数据 - 记录日志:包含请求 URL、
Range值、服务端返回的Content-Range(如有)、Content-Length
断点续传真正的复杂点不在代码行数,而在状态一致性。客户端的 offset 必须始终是服务端响应的镜像,而不是本地计数器。任何“我这边记着呢”的假设,都会在服务端扩容、负载均衡切换或磁盘故障时暴露问题。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











