断点续传原理


断点续传原理

文章插图
 
简述
断点续传:指的是在上传/下载时 , 将任务(一个文件或压缩包)人为的划分为几个部分 , 每一个部分采用一个线程进行上传/下载 , 如果碰到网络故障 , 可以从已经上传/下载的部分开始继续上传/下载未完成的部分 , 而没有必要从头开始上传/下载 。可以节省时间 , 提高速度 。
断点续传的用途
有时用户上传/下载文件需要历时数小时 , 万一线路中断 , 不具备断点续传的 HTTP/FTP 服务器或下载软件就只能从头重传 , 比较好的 HTTP/FTP 服务器或下载软件具有断点续传能力 , 允许用户从上传/下载断线的地方继续传送 , 这样大大减少了用户的烦恼 。
常见的支持断点续传的上传/下载软件:QQ 旋风、迅雷、快车、电驴、酷6、土豆、优酷、百度视频、新浪视频、腾讯视频、百度云等 。
在 linux/Unix 系统下 , 常用支持断点续传的 FTP 客户端软件是 lftp 。
Range & Content-Range
HTTP1.1 协议(RFC2616)开始支持获取文件的部分内容 , 这为并行下载以及断点续传提供了技术支持 。它通过在 Header 里两个参数实现的 , 客户端发请求时对应的是 Range  , 服务器端响应时对应的是 Content-Range 。
Range
用于请求头中 , 指定第一个字节的位置和最后一个字节的位置 , 一般格式:
Range:(unit=first byte pos)-[last byte pos]
Range 头部的格式有以下几种情况:
Range: bytes=0-499 表示第 0-499 字节范围的内容Range: bytes=500-999 表示第 500-999 字节范围的内容Range: bytes=-500 表示最后 500 字节的内容Range: bytes=500- 表示从第 500 字节开始到文件结束部分的内容Range: bytes=0-0,-1 表示第一个和最后一个字节Range: bytes=500-600,601-999 同时指定几个范围【断点续传原理】Content-Range
用于响应头中 , 在发出带 Range 的请求后 , 服务器会在 Content-Range 头部返回当前接受的范围和文件总大小 。一般格式:
Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]
例如:
Content-Range: bytes 0-499/22400
0-499 是指当前发送的数据的范围 , 而 22400 则是文件的总大小 。
而在响应完成后 , 返回的响应头内容也不同:
HTTP/1.1 200 Ok(不使用断点续传方式)
HTTP/1.1 206 Partial Content(使用断点续传方式)
增强校验
在实际场景中 , 会出现一种情况 , 即在终端发起续传请求时 , URL 对应的文件内容在服务器端已经发生变化 , 此时续传的数据肯定是错误的 。如何解决这个问题了?显然此时需要有一个标识文件唯一性的方法 。
在 RFC2616 中也有相应的定义 , 比如实现 Last-Modified 来标识文件的最后修改时间 , 这样即可判断出续传文件时是否已经发生过改动 。同时 FC2616 中还定义有一个 ETag 的头 , 可以使用 ETag 头来放置文件的唯一标识 。
Last-Modified
If-Modified-Since , 和 Last-Modified 一样都是用于记录页面最后修改时间的 HTTP 头信息 , 只是 Last-Modified 是由服务器往客户端发送的 HTTP 头 , 而 If-Modified-Since 则是由客户端往服务器发送的头 , 可以看到 , 再次请求本地存在的 cache 页面时 , 客户端会通过 If-Modified-Since 头将先前服务器端发过来的 Last-Modified 最后修改时间戳发送回去 , 这是为了让服务器端进行验证 , 通过这个时间戳判断客户端的页面是否是最新的 , 如果不是最新的 , 则返回新的内容 , 如果是最新的 , 则返回 304 告诉客户端其本地 cache 的页面是最新的 , 于是客户端就可以直接从本地加载页面了 , 这样在网络上传输的数据就会大大减少 , 同时也减轻了服务器的负担 。
Etag
Etag(Entity Tags)主要为了解决 Last-Modified 无法解决的一些问题 。
一些文件也许会周期性的更改 , 但是内容并不改变(仅改变修改时间) , 这时候我们并不希望客户端认为这个文件被修改了 , 而重新 GET 。
某些文件修改非常频繁 , 例如:在秒以下的时间内进行修改(1s 内修改了 N 次) , If-Modified-Since 能检查到的粒度是 s 级的 , 这种修改无法判断(或者说 UNIX 记录 MTIME 只能精确到秒) 。


推荐阅读