Http系列:断点续传与多线程下载
前言
当下载电影时,我常常会想中断下载后,为什么点击开始时会在中断的地方继续下载呢?
又或者在看在线电影时,为什么可以按着播放条拖动就能看到想看的片段呢?
http的range请求将解决以上困惑。
多线程、断点续传、随机点播等的场景的步骤
1、客户端明确任务:从哪开始下载
- 本地是否已有部分文件:文件已下载部分在服务器端发生改变?
- 使用几个线程并发下载
2、下载文件的指定部分内容
3、下载完毕后拼装成统一的文件
HTTP Range规范
在RFC7233中有详细介绍
1、允许服务器基于客户端的请求只发送响应包体的一部分给到客户端,而客户端自动将多个片段的包体组合成完整的体积更大的包体。
- 支持断点续传
- 支持多线程下载
- 支持视频播放器实时拖动
2、服务器通过Accept-Range头部表示是否支持Range请求
- Accept-Ranges = acceptable-ranges
- 例如:
Accept-Ranges: bytes: 支持;
Accept-Ranges: none: 不支持
Range请求范围的单位
基于字节为单位的时候,举例:设置响应体长度为10000
- 第1个500字节:
bytes=0-499 // 从0开始 - 第2个500字节:
bytes=500-999
bytes=500-600, 601-999
bytes=500-700, 601-999 - 最后1个500字节
bytes=-500
bytes=9500- - 仅要第一个和最后一个字节:bytes=0-0, -1
通过Range头部传递请求范围,如:Range: bytes=0-499
测试
下面用一些小例子有测试一下。
用node搭了一个简单的服务器,返回的数字是22个字节的响应体
'Hello World 0123456789';
现在用curl命令获取全部的响应体,然后访问0-5的字节段:
-H参数添加 HTTP 请求的标头。
上面的命令就是添加HTTP头Range: bytes=0-5。
返回的是Hello (加上空格)一共六个字节。
现在获取第21个字节及以后的字节段,就可以用20-:
返回的是89
Range条件请求
- 如果客户端已经得到了Range响应的一部分,并想在这部分响应未过期的情况下,获取其他部分的响应
常与If-Unmodified-Since或者If-Match头部共同使用 - If-Range = entity-tag / HTTP-date
可以使用Etag或者Last-Modified
测试
下面用etag测试一下Range条件请求
首先获取0-5字节段
然后用-I来看看生成Hello 时服务器生成Etag的值
接下来,用这个值放到If-Match中获取6-10字节段:World
如果Etag发生了变化,来看看结果会怎么样,将最后的0改为1
返回412 Precondition Failed
结论
通过条件请求可以判断两次下载之间,服务器端资源有没有发生变化。如果发生了变化,就可以通过412这个响应知道,资源已经发生了变化。
服务器响应
如果只获取部分的body,那么服务器端返回的响应码不是200,而是206。
206 Partial Content
Content-Range头部:显示当前片段响应体在完整包体中的位置
Content-Range = byte-content-range / other-content-range
{ btye-content-range = bytes-unit SP (byte-range-resp / unsatisfied-range)
byte-range-resp = byte-range '/' (complete-length / '')
complete-length = 1DIGIT // 完整资源的大小,如果未知则用*号替代
bytr-range = first-byte-pos "-" last-byte-pos }例如:
1、Content-Range: bytes 42-1233/1234
2、Content-Range: bytes 42-1233/*
测试
用一个视频播放的例子来看看206响应的样子。
416 Range Not Statisfiable
- 请求范围不满足实际资源的大小,其中Content-Range中的complete-length显示完整响应的长度,例如
Content-Range: bytes */1234
测试
如果获取范围超出实际资源的大小,比如获取30-40。返回416
200 OK
- 服务器不支持Range请求时,则以200返回完整的响应包体
多重范围与multipart
- 请求:
Range: bytes=0-50, 100-150 - 响应:
Content-Type: multipart/byteranges; boundary=...
测试
获取5-10, 10-15片段。
总结
1、客户端通过Range头部传递请求范围
2、服务端返回Accept-Range头部表示是否支持Range请求。
3、客户端如果在得到Range响应的一部分,并想在这部分响应未过期的情况下,获取其他部分的响应,可以用If-Range头部使用Etag或者Last-Modified为值。
4、只获取部分的body,服务器返回206响应码,其中Content-Range头部显示当前片段响应体在完整包体中的位置
5、客户端想多重范围下载资源,在Range头部的格式为Range: bytes=0-50, 100-150...(用逗号分隔)
响应头部Content-Type: multipart/byteranges; boundary=...
作者: zhangwinwin
链接:Http系列:断点续传与多线程下载
来源:github
Http系列:断点续传与多线程下载的更多相关文章
- 图解:HTTP 范围请求,助力断点续传、多线程下载的核心原理
题图:by Charles Loyer 一.序 Hi,大家好,我是承香墨影! HTTP 协议在网络知识中占据了重要的地位,HTTP 协议最基础的就是请求和响应的报文,而报文又是由报文头(Header) ...
- 网络编程之PC版与Android手机版带断点续传的多线程下载
一.多线程下载 多线程下载就是抢占服务器资源 原理:服务器CPU 分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服 ...
- ASP.NET文件下载各种方式比较:对性能的影响、对大文件的支持、对断点续传和多线程下载的支持
asp.net里提供了多种方式,从服务器端向客户端写文件流,实现客户端下载文件.这种技术在做防下载系统时比较有用处.主些技术主要有:WriteFile.TransmitFile和BinaryWrite ...
- 基于http的断点续传和多线程下载
HTTP协议的GET方法,支持只请求某个资源的某一部分: 206 Partial Content 部分内容响应: Range 请求的资源范围: Content-Range 响应的资源范围: 断点续传: ...
- java多线程下载和断点续传
java多线程下载和断点续传,示例代码只实现了多线程,断点只做了介绍.但是实际测试结果不是很理想,不知道是哪里出了问题.所以贴上来请高手修正. [Java]代码 import java.io.File ...
- Java--使用多线程下载,断点续传技术原理(RandomAccessFile)
一.基础知识 1.什么是线程?什么是进程?它们之间的关系? 可以参考之前的一篇文章:java核心知识点学习----并发和并行的区别,进程和线程的区别,如何创建线程和线程的四种状态,什么是线程计时器 简 ...
- android 多线程下载 断点续传
来源:网易云课堂Android极客班第八次作业练习 练习内容: 多线程 asyncTask handler 多线程下载的原理 首先获取到目标文件的大小,然后在磁盘上申请一块空间用于保存目标文件,接着把 ...
- Android开发之多线程下载、断点续传、进度条和文本显示
代码实现了在Android环境下的多线程下载.断点续传.进度条显示和文本显示百分数: import java.io.BufferedReader; import java.io.File; impor ...
- Java开发之多线程下载和断点续传
代码实现了多线程下载和断点续传功能 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream ...
随机推荐
- JavaDailyReports10_10
1.4.2 键盘事件的处理 KeyListener 接口实现了处理键盘事件 KeyEvent 对象描述键盘事件的相关信息. KeyListener 接口有三个方法:KeyPressed K ...
- Mono for android,Xamarin点击事件的多种写法
(一)原本java的写法(相信很多是学过java的): 需要实现接口View.IOnClickListener,最好也继承类:Activity,因为View.IOnClickListener接口又继承 ...
- 关于 RNN 循环神经网络的反向传播求导
关于 RNN 循环神经网络的反向传播求导 本文是对 RNN 循环神经网络中的每一个神经元进行反向传播求导的数学推导过程,下面还使用 PyTorch 对导数公式进行编程求证. RNN 神经网络架构 一个 ...
- 利用PHP递归 获取所有的上级栏目
/** * 获取所有的上级栏目 * @param $category_id * @param array $array * @return array * @author 宁佳兵 <meilij ...
- 学习记录——使用PHP实现数据增删查改等基本功能(前后端分离)
萌新初次学习服务器端语言,分享学习经验 实现功能:1.显示数据表 2.对数据进行分页 3.对数据进行增删查改 由于本萌新采用前后端完全分离方案,所以数据传输用的ajax,为了提高代码的复用 ...
- Serverless 如何应对 K8s 在离线场景下的资源供给诉求
本文整理自腾讯云云原生产品团队的专家产品经理韩沛在 Techo 开发者大会云原生专题的分享内容--Kubernetes 混部与弹性容器.本次分享主要分为三部分:基于 K8s 的应用混部.提升应用混部效 ...
- SQL注入之堆叠注入(堆查询注入)
Stached injection -- 堆叠注入 0x00 堆叠注入的定义 Stacked injection 汉语翻译过来后,称 为堆查询注入,也有称之为堆叠注入.堆叠注入为攻击者提供了很多的 ...
- 【Java基础】多线程
多线程 基本概念 程序(program)是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 进程(process)是程序的一次执行过程,或是正在运行的一个程序.是一个动态 ...
- 【JavaWeb】JSP 页面
JSP 页面 简介 JSP(Java Server Pages),即 Java 的服务器页面.它的主要作用是代替 Servlet 程序回传 HTML 页面的数据,因为 Servlet 程序回传 HTM ...
- CSAPP:Lab0 -Docker搭建纯净Linux环境
1. 安装docker 在mac-os下我们可以利用homebrew很容易的安装docker. brew install docker 当然去官网下载也很容易 Empowering App Devel ...