当前位置: 首页 > news >正文

C++第三方库【httplib】断点续传

什么是断点续传

上图是我们平时在浏览器下载文件的场景,下载的本质是数据的传输。当出现网络异常,浏览器异常,或者文件源的服务器异常,下载都可能会终止。而当异常解除后,重新下载文件,我们希望从上一次下载的位置开始下载,而不是从头开始下载。这就是断点续传

断点续传的实现

ETag头部字段

ETag是用来标识文件的头部字段,由用户自己设定,其目的是表示文件的唯一性,修改过的文件和原文件是不同的。

ETag由服务端设置

static void download(const httplib::Request& req, httplib::Response& resp)
{//......//服务端设置ETag头部字段resp.set_header("ETag", "......");//......
}

浏览器解析响应,发现有ETag字段,保存并在下次发送GET请求时包含。ETag搭配Range字段实现断点续传

Range

当服务端返回的响应中有Accept-Ranges头部字段,代表服务端允许断点续传

客户端此时发送的请求可以携带Range头部字段,形式如下:

//服务端响应设置允许断点续传
static void download(const httplib::Request& req, httplib::Response& resp)
{//......//bytes表示客户端数据请求区间的单位resp.set_header("Accept-Ranges", "bytes");//......
}//客户端请求断点续传区间
static void download(const httplib::Request& req, httplib::Response& resp)
{//......//val是服务端上一次发送的ETagres.set_header("If-Range", ETag);//val的bytes是服务端返回的断点区间的单位//start-end代表重传start到end区间的数据,比如5430-66758res.set_header("Range", "bytes=start-end");//......
}//服务端返回响应
static void download(const httplib::Request& req, httplib::Response& resp)
{//......//响应的文件数据范围是start-end,文件总大小为fsizeresp.set_header("Content-Range, "start-end/fsize");//重新设置ETagresp.set_header("ETag", "......");//......
}
  • 服务端设置Accept-Range字段,val值一般为bytes。该字段表示服务端支持断点续传,以字节单位传输数据
  • ETag表示服务端上某一版本资源的唯一标识,如果资源被改动,则ETag改变。客户端收到ETag表示会保存

当下载中断时,浏览器重新下载文件,则第二次的http请求需要包含If-Range字段和Range字段

  • If-Range字段:保存服务端响应的ETag字段的信息。用于服务端判断是否和上一次请求的资源一致,一致则断点续传,不一致则从头重新下载
  • Range字段:记录断点请求的数据区间,bytes start-end,表示请求服务器资源从第start字节开始到第end个字节的数据

收到客户端发送的断点续传的http响应,需要包含Content-Range字段和ETag字段4

  • Content-Range: start-end/文件大小,表示http响应包含文件数据从start开始到end结束的文件数据,文件大小表示文件总大小
  • ETag:服务端资源的唯一标识

当服务端返回的数据是断点续传的数据区间时,状态码是206

示例断点续传的请求&响应如下:

GET /download/a.txt http/1.1
If-Range: "文件唯一标识"
Range: bytes=89-999
-------------------------------------------
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 89-999/100000
Content-Type: application/octet-stream
ETag: "文件唯一标识"对应文件从89到999字节的数据。

编码实现

使用httplib实现断点续传。

基本逻辑:

  1. 查看客户端请求是否包含If-Range字段,有则匹配请求文件的ETag,没有则是正常下载文件
  2. 若相同,说明客户端请求断点续传,解析Range字段,将start-end的数据填入响应的正文部分。并设置头部字段
  3. 若不同,说明客户端请求的数据被修改了,则需要从头下载,返回文件全部数据。并设置头部字段

以上逻辑,我们需要手动解析客户端响应的Range字段,但httplib已经帮我们解析了,以下源码是httplib做的部分处理

这部分表示,httplib解析客户端请求,如果包含Range字段,会自动设置响应的状态码为206

这部分是httplib解析Range字段,在返回文件数据时,会根据Range字段的解析结果,截断文件数据。所以我们在代码编写时不管是正常下载,还是断点续传都直接响应文件全部数据即可, 如果是断点续传,httplib会帮我们进行数据截断,如果start-end是5430-66347,就截出这部分数据返回给客户端

示例代码如下:

//生成ETag
//ETag = 文件名 + 文件大小 + 文件最后一次修改时间
static std::string getETag(const std::string& filename, const struct stat st)
{std::string ETag;ETag = filename + std::to_string(st.st_size) + std::to_string(st.m_tim);return ETag;
}    //返回客户端要下载的文件
static void download(const httplib::Request& req, httplib::Response& resp)
{//1. 获取客户端请求的资源路径:req.path。截取最后一个/后的字符串,为文件名//2. 根据资源路径,获取文件信息auto pos = req.path.find_last_of('/');std::string filenameif(pos == std::string::npos)filename = req.path;elsefilename = req.path.substr(pos + 1);struct stat st;stat(filename.c_str(), &st);//查看请求是否有If-Range(记录之前服务器响应的ETag)bool retrans = true;std::string old_etag;//有If-Range,两种可能:有修改,全部重传;没有修改,断点续传if(req.has_header("If-Range")){old_etag = req.get_header_value("If-Range");if(old_etag == getETag(info, st))retrans = false;}//4. 读取文件信息到响应中std::ifstream ifs(filename.c_str(), std::ios::binary);//读取文件内容body.resize(st.s_size);ifs.read(&body[0], st.s_size);//5. 设置头部字段resp.set_header("ETag", getETag(info, st));resp.set_header("Accept-Ranges", "bytes");//提供断点续传resp.set_header("Content-Type", "application/octet-stream");//下载文件if(retrans){//文件有修改,需要重传文件//ETag  Accept-Ranges bytes(断点续传)resp.status = 200;}else{//断点续传实现:获取头部字段中Range:bytes start-end,解析请求文件的起始和结束//再返回响应时,对文件内容进行截断//但httplib都实现了,他检测到req中有Range,然后进行处理,甚至会设置resp的状态码//我们只要返回完整的文件,httplib会对文件进行截断,最后响应正文中只有start-end的文件内容//resp.set_header("Content-Range", "bytes start-end/fsize");//原本还要设置这个头部字段,httplib帮我们做了resp.status = 206;//断点续传的状态码}
}

相关文章:

C++第三方库【httplib】断点续传

什么是断点续传 上图是我们平时在浏览器下载文件的场景,下载的本质是数据的传输。当出现网络异常,浏览器异常,或者文件源的服务器异常,下载都可能会终止。而当异常解除后,重新下载文件,我们希望从上一次下载…...

[SaaS] AI+数据,tiktok选品,找达人,看广告数据

TK观察专访丨前阿里“鲁班”创始人用AIGC赋能TikTok获千万融资用AI数据做TikTokhttps://mp.weixin.qq.com/s/xp5UM3ROo48DK4jS9UBMuQ主要还是爬虫做数据的。 商家做内容:1.找达人拍内容,2.商家自己做原生自制内容,3.广告内容。 短视频&…...

A股冲高回落,金属、地产板块领跌,新股N汇成真首日暴涨753%

行情概述 AH股有色金属、教育及地产板块领跌,军工航天及半导体板块逆势走强;锂电池、创新药概念股也走强。创业板新股N汇成真首日暴涨753%,触发二次临停。 周三A股冲高回落,上证指数收跌0.83%,深成指跌0.8%&#xff…...

dns域名解析服务和bond网卡

目录 dns域名解析服务 一、DNS 1、定义 2、以www.baidu.com为例 3、域名体系结构 4、DNS解析使用的协议和端口 5、dns域名解析的过程 6、dns解析的优先级 二、如何实现域名解析 1、域名解析 2、bind配置文件位置 (一)正向解析 (…...

视频生成框架EasyAnimate正式开源!

近期,Sora模型的热度持续上涨,社区中涌现了一些类Sora的开源项目,这些项目均基于Diffusion Transformer结构,使用Transformer结构取代了UNet作为扩散模型的基线,旨在生成更长、更高分辨率、且效果更好的视频。EasyAnim…...

【微机原理与汇编语言】并行接口8255实验

一、实验目的 掌握可编程并行接口芯片8255的工作原理及初始化方法掌握8255在实际应用中的硬件连接及编程应用 二、实验要求 根据实验室现有条件,针对实验任务,设计实验方案并进行实现。 三、实验内容 启动0#计数器,每计5个数&#xff08…...

Oracle表分区的基本使用

什么是表空间 是一个或多个数据文件的集合,所有的数据对象都存放在指定的表空间中,但主要存放的是表,所以称为表空间 什么是表分区 表分区就是把一张大数据的表,根据分区策略进行分区,分区设置完成之后,…...

6月5号作业

设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数 ​ #include <iostream>using namespace std; class Slu { priv…...

中继器、集线器、网桥、交换机、路由器和网关

目录 前言一、中继器、集线器1.1 中继器1.2 集线器 二、网桥、交换机2.1 网桥2.1.1 认识网桥2.1.2 网桥的工作原理2.1.3 生成树网桥 2.2 交换机2.2.1 交换机的特征2.2.2 交换机的交换模式2.2.3 交换机的功能 三、路由器、网关3.1 路由器的介绍3.2 路由器的工作过程3.2.1 前置知…...

揭秘相似矩阵:机器学习算法中的隐形“纽带”

在机器学习领域&#xff0c;数据的处理和分析至关重要。如何有效地从复杂的数据集中提取有价值的信息&#xff0c;是每一个机器学习研究者都在努力探索的问题。相似矩阵&#xff0c;作为衡量数据之间相似性的数学工具&#xff0c;在机器学习算法中扮演着不可或缺的角色。 相似矩…...

攻防世界—webbaby详解

1.ssrf注入漏洞 ssrf&#xff08;服务端请求伪造&#xff09;是一种安全漏洞&#xff0c;攻击者通过该漏洞向受害服务器发出伪造的请求&#xff0c;从而访问并获取服务器上的资源&#xff0c;常见的ssrf攻击场景包括访问内部网络的服务&#xff0c;执行本地文件系统命令&#…...

MySQL中:cmd下输入命令mysql -uroot -p 连接数据库错误

目录 问题cmd下输入命令mysql -uroot -p错误 待续、更新中 问题 cmd下输入命令mysql -uroot -p错误 解决 配置环境变量&#xff1a;高级系统设置——环境变量——系统变量——path编辑——新建——MySQL.exe文件路径&#xff08;如下图所示&#xff09; phpstudy2018软件下&am…...

【开发利器】使用OpenCV算子工作流高效开发

学习《人工智能应用软件开发》&#xff0c;学会所有OpenCV技能就这么简单&#xff01; 做真正的OpenCV开发者&#xff0c;从入门到入职&#xff0c;一步到位&#xff01; OpenCV实验大师Python SDK 基于OpenCV实验大师v1.02版本提供的Python SDK 实现工作流导出与第三方应用集…...

基础数学-求平方根(easy)

一、问题描述 二、实现思路 1.题目不能直接调用Math.sqrt(x) 2.这个题目可以使用二分法来缩小返回值范围 所以我们在left<right时 使 mid (leftright)/21 当mid*mid>x时&#xff0c;说明right范围过大&#xff0c;rightright-1 当mid*mid<x时&#xff0c;说明left范…...

c语言项目-贪吃蛇项目2-游戏的设计与分析

文章目录 前言游戏的设计与分析地图&#xff1a;这里简述一下c语言的国际化特性相关的知识<locale.h> 本地化头文件类项setlocale函数 上面我们讲到需要打印★&#xff0c;●&#xff0c;□三个宽字符找到这三个字符打印的方式有两种&#xff1a; 控制台屏幕的长宽特性&a…...

力扣2831.找出最长等值子数组

力扣2831.找出最长等值子数组 思路&#xff1a;用二维数组存每个数字的出现下标 遍历所有数字求结果当前子数组大小&#xff1a;pos[i] - pos[j] 1;当前相同数个数&#xff1a;i - j 1;需要删去的数的个数&#xff1a;pos[i] - pos[j] - i j; class Solution {public:int…...

17K star,一款开源免费的手机电脑无缝同屏软件

导读&#xff1a;白茶清欢无别事&#xff0c;我在等风也等你。 作为程序员&#xff0c;在我们的工作中经常需要把手机投票到电脑进行调试工作&#xff0c;选择一款功能强大的投屏软件是一件很必要的事情。今天给大家介绍一款开源且免费的投屏软件&#xff0c;极限投屏&#xff…...

正则表达式二

修饰符 i&#xff1a;将匹配设置为不区分大小写&#xff0c;即A和a没有区别 var str"Google Runoob taobao runoob"; var n1str.match(/runoob/g); //runoob var n2str.match(/runoob/gi); //Runoob&#xff0c;runoobg&#xff1a;重找所有匹配项&#xff0…...

我的创作纪念日--我和CSDN一起走过的1825天

机缘 第一次在CSDN写文章&#xff0c;是自己在记录学习Java8新特性中Lambda表达式的内容过程中收获的学习心得。之前也有记录工作和生活中的心得体会、难点的解决办法、bug的排查处理过程等等。一直都用的有道笔记&#xff0c;没有去和大家区分享的想法&#xff0c;是一起的朋…...

递归书写树形图示例

大叫好&#xff0c;今天书写了一个扁型转换为树型的例子&#xff0c;使用的是递归&#xff0c;请大家食用&#xff0c;无毒 <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><meta name"viewport" conte…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...