前言

当下载电影时,我常常会想中断下载后,为什么点击开始时会在中断的地方继续下载呢?
又或者在看在线电影时,为什么可以按着播放条拖动就能看到想看的片段呢?

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 = 1
    DIGIT // 完整资源的大小,如果未知则用*号替代
    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系列:断点续传与多线程下载的更多相关文章

  1. 图解:HTTP 范围请求,助力断点续传、多线程下载的核心原理

    题图:by Charles Loyer 一.序 Hi,大家好,我是承香墨影! HTTP 协议在网络知识中占据了重要的地位,HTTP 协议最基础的就是请求和响应的报文,而报文又是由报文头(Header) ...

  2. 网络编程之PC版与Android手机版带断点续传的多线程下载

    一.多线程下载         多线程下载就是抢占服务器资源         原理:服务器CPU 分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服 ...

  3. ASP.NET文件下载各种方式比较:对性能的影响、对大文件的支持、对断点续传和多线程下载的支持

    asp.net里提供了多种方式,从服务器端向客户端写文件流,实现客户端下载文件.这种技术在做防下载系统时比较有用处.主些技术主要有:WriteFile.TransmitFile和BinaryWrite ...

  4. 基于http的断点续传和多线程下载

    HTTP协议的GET方法,支持只请求某个资源的某一部分: 206 Partial Content 部分内容响应: Range 请求的资源范围: Content-Range 响应的资源范围: 断点续传: ...

  5. java多线程下载和断点续传

    java多线程下载和断点续传,示例代码只实现了多线程,断点只做了介绍.但是实际测试结果不是很理想,不知道是哪里出了问题.所以贴上来请高手修正. [Java]代码 import java.io.File ...

  6. Java--使用多线程下载,断点续传技术原理(RandomAccessFile)

    一.基础知识 1.什么是线程?什么是进程?它们之间的关系? 可以参考之前的一篇文章:java核心知识点学习----并发和并行的区别,进程和线程的区别,如何创建线程和线程的四种状态,什么是线程计时器 简 ...

  7. android 多线程下载 断点续传

    来源:网易云课堂Android极客班第八次作业练习 练习内容: 多线程 asyncTask handler 多线程下载的原理 首先获取到目标文件的大小,然后在磁盘上申请一块空间用于保存目标文件,接着把 ...

  8. Android开发之多线程下载、断点续传、进度条和文本显示

    代码实现了在Android环境下的多线程下载.断点续传.进度条显示和文本显示百分数: import java.io.BufferedReader; import java.io.File; impor ...

  9. Java开发之多线程下载和断点续传

    代码实现了多线程下载和断点续传功能 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream ...

随机推荐

  1. springMVC搭建分布式框架

    https://www.cnblogs.com/lr393993507/p/7652717.html https://www.cnblogs.com/Tpf386/p/10987931.html

  2. 在搜索引擎中输入汉字就可以解析到对应的域名,请问如何用LoadRunner进行测试。

    建立测试计划,确定测试标准和测试范围 设计典型场景的测试用例,覆盖常用业务流程和不常用的业务流程等 根据测试用例,开发自动测试脚本和场景: 录制测试脚本:新建一个脚本(Web/HTML协议):点 ...

  3. 你的项目中使用过哪些JSTL标签?

    项目中主要使用了JSTL的核心标签库,包括< c:if>.< c:choose>.< c: when>.< c: otherwise>.< c:f ...

  4. hive之Json解析(普通Json和Json数组)

    一.数据准备 现准备原始json数据(test.json)如下: {"movie":"1193","rate":"5", ...

  5. go语言环境搭建以及配置VSCode

    Go语言学习笔记(环境安装)-day01 Go语言运行环境安装 下载Go安装包 安装包地址 安装Go语言运行环境 ​ 直接在下载好的目录双击运行*.msi的可执行文件,下一步进行安装,安装的目录最好是 ...

  6. Java 实现简单的 Socket 通信

    Java socket 封装了传输层的实现细节,开发人员可以基于 socket 实现应用层.本文介绍了 Java socket 简单用法. 1. 传输层协议 传输层包含了两种协议,分别是 TCP (T ...

  7. Debian安装HomeBrew

    前言 HomeBrew 的用处我想使用 Mac 的开发人员都知道, 本篇讲解如何在 Debian 上安装 BrewLinux 更新: 后来发现并不是很好用, 不建议使用 官方推荐的脚本安装 注意这里只 ...

  8. MVC和MVVM的差别

    MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码 ...

  9. Openstack Nova 添加计算节点(六.一)

    Openstack Nova 添加计算节点(六.一) # 重要的两点: 1 时间同步 2 yum 源 # 安装软件: yum install openstack-selinux openstack-n ...

  10. Python运维自动化psutil 模块详解(超级详细)

    psutil 模块 参考官方文档:https://pypi.org/project/psutil/ 一.psutil简介 psutil是一个开源且跨平台(http://code.google.com/ ...