c++如何实现文件下载的断点续传逻辑_HTTP Range头处理【实战】

老伟大大_4085

老伟大大_4085

2026-04-12

169人浏览

原创

断点续传核心是正确使用http range头并严格校验服务器响应。需先head检查accept-ranges,用libcurl的curlopt_range设置范围,解析content-range响应头确认实际返回区间,以r+b模式定位写入,预分配文件大小,原子化持久化偏移状态,416时降级全量下载或清理重试。

c++如何实现文件下载的断点续传逻辑_http range头处理【实战】

如何用 C++ 发起带 Range 的 HTTP 请求

断点续传的核心是让服务器只返回文件的一部分,这依赖于 HTTP Range 请求头。C++ 本身不内置 HTTP 客户端,得靠第三方库(如 libcurl)实现。关键不是“能不能发”,而是“怎么发才被服务器正确响应”。

常见错误:直接拼接 "Range: bytes=1024-" 但没检查服务器是否支持;或用了 Range 却没处理 416 Requested Range Not Satisfiable 错误。

  • 必须在请求头中显式设置 Range: bytes=<start>-<end></end></start>(<end></end> 可省略表示到末尾)
  • 发起前先 HEAD 请求,检查响应头是否含 Accept-Ranges: bytes,否则断点续传不可行
  • libcurl 中用 curl_easy_setopt(curl, CURLOPT_RANGE, "0-1023") 更安全,它会自动加头并处理部分逻辑
  • 别忽略 Content-Range 响应头——它告诉你实际返回了哪一段,比如 bytes 1024-2047/1048576,必须校验 start 和 length 是否匹配预期

本地文件写入时如何安全追加并校验偏移

下载中断后重新开始,不能简单 fopen(..., "wb") 覆盖,也不能无脑 "ab" 追加——因为网络可能重复返回同一段、或服务器响应错乱。

正确做法是:以 "r+b" 打开已有文件,fseek() 到目标偏移再写;同时记录已写长度,避免覆盖未完成块。

  • 首次下载前创建空文件并用 ftruncate() 预分配大小(需从 Content-Range 或 HEAD 的 Content-Length 获取总长)
  • 每次写入前用 fseek(fp, offset, SEEK_SET) 定位,再用 fwrite() 写入,避免指针错位
  • 写完立即调用 fflush(fp),防止缓冲区滞留导致断电后丢失最后一段
  • 建议每写 64KB 后用 fsync() 强刷磁盘(Linux/macOS),Windows 用 _commit()

如何持久化断点状态并避免多线程冲突

程序崩溃或用户关闭后,得知道“上次下到哪了”。这个状态不能只存在内存里,也不能靠文件大小反推——因为写入可能中途失败、校验未通过。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

最简方案是单独存一个元数据文件(如 file.zip.part),里面只写当前已确认完成的字节偏移。

  • 每次成功写入并校验 CRC32 或 MD5 片段后,原子更新元数据文件(先写临时文件,再 rename() 覆盖)
  • 恢复时读元数据 → 截断文件至该偏移 → 从该位置发起 Range 请求
  • 若用多线程分段下载(如 4 线程各下 1/4),每个线程必须独占自己的偏移区间,且元数据要记录每段的完成状态(例如 JSON:{"0": 1048576, "1": 1, "2": 0, "3": 1048576})
  • 避免用全局变量存偏移量——线程 A 更新了,线程 B 还在用旧值,结果重叠写入

遇到 416 或 206 响应时该怎么处理

206 Partial Content 是理想响应,但现实里常碰到 416:要么服务器不支持 Range,要么你算错了 start(比如超过了文件总大小),或者中间文件被手动删改过。

这时候不能直接报错退出,而要降级为全量重下,或提示用户清理残留文件。

  • 收到 416 时,检查响应头中的 Content-Range: */<total></total>,提取 <total></total>;若为空,说明服务器根本不支持断点,改用 GET 全量下载
  • 若 <total></total> 小于本地记录的“预期总长”,说明服务器文件已变更(如被更新),应清空本地文件和元数据,重新 HEAD
  • libcurl 默认把 416 当作错误返回,需设置 curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0L) 才能捕获响应码
  • 不要假设 206 一定对应你请求的范围——务必解析 Content-Range 头,比对起始/结束值,不一致就 abort

真正难的不是发一个 Range 请求,而是把偏移管理、文件 I/O、异常恢复、多线程协同这几层逻辑串成一条不掉链子的流水线。尤其注意:服务器返回的 Content-Range 和你本地记录的 offset 必须严格一致,差 1 字节都可能导致后续所有数据错位。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++ c++文件处理

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

2023.08.07

2175

5

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.23

3382

1

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

2023.10.13

1136

3

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

2025.09.10

3879

7

curl_exec
curl_exec

curl_exec函数是PHP cURL函数列表中的一种,它的功能是执行一个cURL会话。给大家总结了一下php curl_exec函数的一些用法实例,这个函数应该在初始化一个cURL会话并且全部的选项都被设置后被调用。他的返回值成功时返回TRUE, 或者在失败时返回FALSE。

2023.06.14

3683

6

linux常见下载安装工具
linux常见下载安装工具

linux常见下载安装工具有APT、YUM、DNF、Snapcraft、Flatpak、AppImage、Wget、Curl等。想了解更多linux常见下载安装工具相关内容,可以阅读本专题下面的文章。

2023.10.30

835

4

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

2025.09.18

4685

12

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

2025.09.18

1970

13

c++ 全局变量
c++ 全局变量

本专题整合了c++全局变量的使用、定义、作用域等等内容,阅读专题下面的文章了解更多详细内容。

2026.03.17

199

17

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习