菜鸟笔记
提升您的技术认知

断点续传实现原理

我们都用过网盘,不管是例如百度网盘之类的公共网盘,还是自己搭建的私有网盘,都会或多或少的涉及到断点续传和秒传。断点续传和秒传大大提高了网盘上传的效率,下面我们就来讲解一下这两种技术的具体原理和实现,这里的讲解不涉及任何前后端编程语言,适合所有语言开发人员阅读。

零、断点续传

这里以上传为例,下载方式的断点续传类似。

简述原理

断点续传说白了就是将一个文件按照一定的规则人为的分割成多个小文件,然后客户端每次只上传一个小文件(当然我们也可以利用多线程技术每次上传多个小文件),服务器接收到上传过来的小文件后根据一定的规则来组合这些小文件。如果在上传过程中出现网络中断等意外情况,下次再次上传时可以从已经上传的部分继续上传,而不是重新上传。

详细讲解

从 HTTP1.1 协议开始就已经支出获取文件的部分内容,断点续传技术就是利用 HTTP1.1 协议的这个特点在 Header 里添加两个参数来实现的。这两个参数分别是客户端请求时发送的 Range 和服务器返回信息时返回的 Content-Range - Range,Range 用于指定第一个字节和最后一个字节的位置,格式如下:

Range:(unit=first byte pos)-[last byte pos]

Range 常用的格式有如下几种情况:

Range:bytes=0-1024 ,表示传输的是从开头到第1024字节的内容;Range:bytes=1025-2048 ,表示传输的是从第1025到2048字节范围的内容;Range:bytes=-2000 ,表示传输的是最后2000字节的内容;Range:bytes=1024- ,表示传输的是从第1024字节开始到文件结束部分的内容;Range:bytes=0-0,-1 表示传输的是第一个和最后一个字节 ;Range:bytes=1024-2048,2049-3096,3097-4096 ,表示传输的是多个字节范围。Content-Range Content-Range 用于响应带有 Range 的请求。服务器会将 Content-Range 添加在响应的头部,格式如下:

Content-Range:bytes(unit first byte pos)-[last byte pos]/[entity length]

常见的格式内容如下:

Content-Range:bytes 2048-4096/10240

这里边 2048-4096 表示当前发送的数据范围, 10240 表示文件总大小。

这里我顺便说一下,如果在客户端请求报文头中,对 Range 填入了错误的范围值,服务器会返回 416 状态码。416 状态码表示服务器无法处理所请求的数据区间,常见的情况是请求的数据区间不在文件范围之内,也就是说,Range 值,从语法上来说是没问题的,但从语义上来说却没有意义。

注意:当使用断点续传的方式上传下载软件时 HTTP 响应头将会变为:

HTTP/1.1 206 Partial Content

当然光有 Range 和 Content-Range 还是不够的,我们还要知道服务端是否支持断点续传,只需要从如下两方面判断即可:

判断服务端是否只 HTTP/1.1 及以上版本,如果是则支持断点续传,如果不是则不支持 服务端返回响应的头部是否包含 Access-Ranges ,且参数内容是 bytes 符合以上两个条件即可判定位支持断点续传。

校验

这里的校验主要针对断点续传下载来说的。当服务器端的文件发生改变时,客户端再次向服务端发送断点续传请求时,数据肯定就会发生错误。这时我们可以利用 Last-Modified 来标识最后的修改时间,这样就可以判断服务器上的文件是否发生改变。和 Last-Modified 具有同样功能的还有 if-Modified-Since,它俩的不同点是 Last-Modified 由服务器发送给客户端,而 if-Modified-Since 是由客户端发出, if-Modified-Since 将先前服务器发送给客户端的 Last-Modified 发送给服务器,服务器进行最后修改时间验证后,来告知客户端是否需要重新从服务器端获取新内容。客户端判断是否需要更新,只需要判断服务器返回的状态码即可,206 代表不需要重新获取接着下载就行,200代表需要重新获取。 但是 Last-Modified 和 if-Modified-Since 存在一些问题:

某些文件只是修改了修改时间而内容却没变,这时我们并不希望客户端重新缓存这些文件;

某些文件修改频繁,有时一秒要修改十几次,但是 if-Modified-Since 是秒级的,无法判断比秒更小的级别; 部分服务器无法获得精确的修改时间。 要解决上述问题我们就需要用到 Etag ,只需将相关标记(例如文件版本号等)放在引号内即可。

当使用校验的时候我们不需要手动实现验证,只需要利用 if-Range 结合 Last-Modified 或者 Etage 来判断是否发生改变,如果没有发生改变服务器将向客户端发送剩余的部分,否则发送全部。

注意:If-Range 必须与 Range 配套使用。缺少其中任意一个另一个都会被忽略。

秒传

原理

秒传利文件的MD5,首先将文件的MD5发送个服务器,服务器传输过来的MD5判断服务器上是否存在相同类型的文件,如果存在就将文件复制一份,而不是本地上传。这样就是先的秒传功能。

MD5

秒传涉及到了MD5,那么什么MD5呢?MD5的英文全称是 Message-Digest Algorith 5 ,是计算机广泛使用的算法之一。 MD5 会为文件产生唯一的“指纹”,任何改动都会改变文件指纹。它以 512位分组来处理信息,每个分组又被分为16个32位分组,经过处理后输出4个32位分组,最后将输出的4个32位分组进行级联生成128位散列值。

MD5的具有压缩性、易计算、抗修改、弱抗碰撞和强抗碰撞。下面我们一一来讲解:

压缩性:任意长度数据,生成的MD5值长度是固定的;易计算:可以很方便的从原始数据计算出MD5;抗修改:对原始数据的任何修改,都会改变MD5;弱抗碰撞和强抗碰撞:很难找到具有相同MD5的数据。破解谣言:有人说网盘能秒传证明数据在网盘服务器是不加密的,有数据库查看权限的人都可以看,所以私密文件最好在本地磁盘加密后再上传到网盘中。这句话是错误的,正规的网盘服务器只是验证了文件的MD5码,文件还是加密存放的。

总结

这篇文章讲解了断点续传和秒传的知识,也讲解了它们所使用技术的相关知识点。这些知识可以用在任何编程语言的断点续传和秒传的开发中,因此这篇文章我并没有根据具体的语言讲解。