#原理:

因为断点续传真的用不了http头部的几个字段,没办法,他只能自己来规定协议了。但是它们都还是需要RandomAccessFile。

其实通常性的原理都是分块分片。协议1虽说可以实现断点续传,不过他针对一个大文件只会有一个sourceid,它可以实现续传,但并不能提高上传的性能。

只有通过对一个大文件分片分块,然后并发上传,这样才能提升上传的性能。

#自己规定协议1

客户端第一次上传时向服务端发送“Content-Length=35;filename=WinRAR_3.90_SC.exe;sourceid=“这种格式的字符串,服务端收到后会查找该文件是否有上传记录,如果有就返回已经上传的位置,否则返回新生成的sourceid以及position为0,类似”sourceid=2324838389;position=0“这样的字符串,客户端收到返回后的字符串后再从指定的位置开始上传文件。

文件上传服务端

http://www.apkbus.com/data/attachment/forum/201112/20/1848519wkk73w2v0w007kx.jpg

文件上传客户端

http://www.apkbus.com/data/attachment/forum/201112/20/184848pajfr1zj2aagz4zg.jpg

#分块上传:自己规定的协议2
很像分页的算法

{
 Char filename[50];文件名
 char filetype[20];文件类型
 int filesize;文件大小
 int blocknum;总块数
 int blockno;当前块号
 }

上传文件首先获取文件的属性信息如果文件大于1M,以1M大小来分块,每块添加上面结构体中的内容为头,也就是每次传输1M+82byte;最后一块可能不到1M,服务器端在计算的时候需要注意.
服务器端接收到内容后根据以上规则拼凑。
如果文件为视频文件非常大可以5个一起上传来提高效率。

目前断点续传是借助分块上传实现的,每上传成功一个分块,服务端需要把这个分块记住,下次在文件上传前服务端先把已成功的分块告诉前端,前端可以判断某个分块,检测此分块是否已经上传过,上传过则跳过此分块。

一种更具体的做法:
前台文件分片上传(即android客户端),分片计算md5;后台接收分片成功(放在temp文件夹),把分片号,分片md5和文件md5存入 缓存(redis);分片上传完成,取出所有分片合并文件,保存到数据库,文件移动到正式的文件系统; 如果分片上传一部分后,前台中断了;下次续传,根据文件和分片MD5判断有多少分片已经上传,跳过。所有分片上传完成后,合并文件。

#分块上传:自己规定的协议3

以下是七牛的协议,可能未来这篇文章会被删除,所以就复制过来了,文章如下:

http://developer.qiniu.com/docs/v6/api/overview/up/chunked-upload.html

分片上传(断点续上传)

分片上传功能支持将一个文件切割为一系列特定大小的小数据片,分别将这些小数据片分别上传到服务端,全部上传完后再在服务端将这些小数据片合并成为一个资源。上传模型中对分片上传的特点进行了完整的阐述。

##关键概念

分片上传引入了两个概念:块(block)和片(chunk)。每个块由一到多个片组成,而一个资源则由一到多个块组成。他们之间的关系可以用下图表述:

android 下载断点续传 安卓断点续传原理_android 下载断点续传

##资源、块、片的关系

块是服务端的永久数据存储单位,片则只在分片上传过程中作为临时存储的单位。服务端会以约一个月为单位周期性的清除上传后未被合并为块的数据片。

##基本流程

与分片上传相关的API有这几个:创建块(mkblk)、上传片(bput)、创建资源(mkfile)。一个完整的分片上传流程可用下图表示:

android 下载断点续传 安卓断点续传原理_服务端_02

##分片上传流程

其中的关键要点如下:

将待上传的文件按预定义的4MB块大小切分为若干个块。如果这个文件小于4MB,当然也就只有一个块;
将每个块再按预定义的片大小切分为若干个片,先在服务端创建一个相应块(通过调用mkblk,并带上第一个片的内容),然后再循环将所有剩下的片全部上传(通过调用bput,从而完成一个块的上传);
在所有块上传完成后,通过调用mkfile将这些上传完成的块信息再严格的按顺序组装出一个逻辑资源的元信息,从而完成整个资源的分片上传过程。
如要更准确的理解这个基本流程,可以通过阅读SDK源代码。所有SDK的源代码都公开托管在Github上。

##并发上传

由于之前介绍的片上传过程中的Context机制,每个块内部只能按顺序逐一上传该块所切分好的片。而每个块之间相互独立,因此若干个块可以同时进行传输而不会相互干扰,因此我们可以利用这个特征实现并发上传特性。

每个文件对应的最大理论并发上传数量也即该文件可划分的块数量。当然这个理论数量也受到很多其他因素的制约,比如像iOS限定了每个APP最多只能开4个并发HTTP连接,也即在iOS上,无论有多少个块,最大的并发上传数量不可能超过4个。并不是并发数量越大上传速度就会越快。因此在实际开发中,通常会使用线程池(Thread Pool)技术来控制并发数量。

##断点续传

虽然片的存在周期并非永久,但已足以实现断点续传机制。

每成功上传一个片,客户端都会收到服务端返回一个代表当前已上传多少片的进度信息,我们称之为Context。上传下一个片时应提供前一个片上传成功后返回的Context。因此,这个Context可以认为是片传输进度的一个标记。

如果上传过程中,服务端发现一个块已经被片数据装满,那么最后一个片上传成功后返回的Context将是一个特殊的值EOB,告诉客户端不要再往这个块附加更多的片。

如果客户端在每次收到Context信息时都将其持久化到本地,即使客户端程序意外崩溃或正常重启,都可以在启动时读取上一次上传成功的片对应的Context,从而接着继续传输剩余片。这个效果我们称之为断点续传。

断点续传功能在上传一个需要较长时间比如一天时间才能上传完毕的大文件时尤其有价值,毕竟我们很难保证这段很长的时间内客户端都不会被关闭,且网络也一直处于连接状态。当前主流的移动平台(iOS、Android、Windows Phone 8)都有监测非活动应用并自动将其关闭的功能,这意味着在移动平台上我们要上传一个大文件时更容易遇到中途程序突然被关闭的情况,断点续传也就更有价值。

支持断点续传功能之后,在客户端很自然可以支持一个新功能:暂停或恢复某个文传的上传过程。

##上传后续动作

我们曾在上传模型中提过,在上传时开发者可以指定上传完成后服务端的后续动作,比如回调、自定义返回内容、303重定向等。可设置的后续动作与表单上传中完全一致。

这里需要明确的是,虽然后续动作在生成上传凭证时已经指定,但这些后续动作只在服务端处理完mkfile请求后才会发生,而且也只有mkfile请求的内容可以包含变量。

##总体思考

毕竟七牛是专业做存储的,对上传下载的性能要求肯定高。粒度分得更为细致了,越精细化,效率提升的反而越高吧。

#参考资料

http://hao3100590.iteye.com/blog/1295903

http://www.eoeandroid.com/thread-548327-1-1.html?_dsign=b7b5889a

http://www.apkbus.com/thread-18964-1-1.html

http://www.zuidaima.com/blog/2819949848316928.htm

http://developer.qiniu.com/docs/v6/api/overview/up/chunked-upload.html