先说说断点续传的原理:这是HTTP 1.1协议的一部分,并不需要客户端特意去做多么复杂的事情。以前我曾经看过一个单位的技术标书,其中有下载的断点续传这一要求,给出的offer居然还挺高的...
简单的说,只要利用了HTTP协议(http://www.ietf.org/rfc/rfc2616.txt)中的如下字段来和服务器端交互,就可以实现文件下载的断点续传:
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 下载第一以及最后一个字节的内容(这个看上去有点变态...)
Accept-Ranges : 用于服务器端到客户端的应答,客户端通过该字段可以判断服务器是否支持断点续传(注意RFC中注明了这一部分并不是必须的)。格式如下:
Accept-Ranges: bytes 表示支持以bytes为单位进行传输。
Accept-Ranges: none 表示不支持
Content-Ranges : 用于服务器端到客户端的应答,与Accept-Ranges在同一个报文内,通过该字段指定了返回的文件资源的字节范围。格式如下:
Content-Ranges: bytes 0-499/1234 大小为1234的文件的第0-499字节范围的内容
Content-Ranges: bytes 734-1233/1234 大小为1234字节的文件的第734-结尾范围的内容
据此我们可以知道,断点续传这个功能是需要客户端和服务器端同时支持才能完成。
Android平台面向开发者提供了DownloadManager这个服务(service),可以用来完成下载,同时异步地得到下载进度的实时更新提示。原生的浏览器,Android Market以及GMail等客户端都使用了该接口。该接口也部分的提供了断点续传功能:如果在下载过程中遇到网络错误,如信号中断等,DownloadManager会在网络恢复时尝试断点续传继续下载该文件。但不支持由用户发起的暂停然后断点续传。
要扩展该功能也不难,只要为下载任务新增一种状态(类似paused_by_user),以及相关逻辑即可,这里暂不赘述,把话题引到一些常见问题上。
1. 关于ETag
RFC中的定义有些抽象,简单的说,ETag可以用来标识/保证文件的唯一性或完整性,你可以把它看作是服务器为某个文件生产的唯一标识值,每次文件有更新该值就会变化。通过这种机制客户端可以检查某个文件在断点续传(当然它不仅仅用于断点续传)的前后是否有所改动:如果ETag改变了就应该重新下载整个文件以保证它的完整性。
但是在现实环境中,有一些服务器并不返回ETag字段,同时它又是支持断点续传的,这种情况下原生的Android就会认为服务器端不支持断点续传。这应该不是什么bug,仅仅是这么实现而已。还有更麻烦的情况是,有些服务器给了错误的ETag,但文件是从未更改的,这时候要想从客户端修改这个“bug”,估计只能忽略ETag值了。
2. 关于HTTP 206
RFC中定义了断点续传时服务器端的应答情况:如果支持且返回的内容如请求所要求的那样,是该文件的一部分,则使用HTTP 206状态码;如果不支持,或需要返回整个文件,则使用HTTP 200状态码。但是现实网络中有些服务器不管三七二十一,都返回200。没办法,如果还是想从客户端来修改这个“bug”,那就多做一些判断处理吧:如果服务器指定了“Content-Ranges”,就忽略HTTP 200的状态码。
附图一张,简述流程。
补记:有一次被问起如何在原生的Android手机上暂停一个下载任务,回头再断点续传。我想是不是可以在下载过程中将手机信号关闭,下次再打开手机信号时,那个下载任务就可以自动接着续传了(当然前提是服务器支持)...这个用例没多大实用价值,懒得实测了。
以下内容转自:http://www.android123.com.cn/androidkaifa/932.html
对于Android平台,很多网友可能考虑开发一个软件商店,对于Android平台上如何实现断点续传操作呢? 这里Android123给大家一些思路和原理的介绍,同时在Android手机上要考虑的一些事情。
1. 流量控制,获取运营商的接入方式,比如说使用移动网络接入,尽可能的提示用户切换WiFi或提示,限制下载的流量以节省话费。
2. 屏幕锁控制,屏幕锁屏后导致应用会被挂起,当然Android提供了PowerManager.WakeLock来控制。
3. 对于断点续传,这要追溯到Http 1.1的特性了,主要是获取文件大小,如果这个无法读取的话,那么就无法断点续传了只能使用chunked模式了,当然获取远程服务器上文件的大小可以通过Http的响应头查找Content-Length。
4. 获取上次文件的更改时间,对于断点续传来说比较有风险的就是 继续下载的文件和早期下载的在server上有变动,这将会导致续传时下载的文件版本和原始的不同,一般有两种解决方法,早期我们配置服务器时通过Last-Modified这个http header获取文件上次修改时间,不过本次Android开发网推荐使用更为强大的ETag,ETag一般用于解决同一个URL处理不同返回相应,比如Session认证,多国语言,以及部分黑帽的SEO中。具体的实现大家可以参考RFC文档。
5. 考虑服务器的3xx的返回,对于专业的下载文件服务器会考虑到负载平衡问题,这就涉及到重定向问题,处理重定向使用Android的Apache库处理比较好。
6. 至于多线程,这里CWJ提示大家可能存在独立的线程下载一个文件,和多个线程分块下载单个文件之分,其中后者需要考虑上次下载数据是否存在问题,同时如果服务器不支持文件大小获取,则无法通过分段下载数据,因为不知道如何分段,所以在chunked模式中,只能使用一个线程下载一个文件,而不是多个线程下载一个文件。
7. 下载后的数据效验,可以考虑CRC等方式,当然对于一般的传输只要逻辑不出现问题,基本上不会有偏差。
8. 考虑DRM问题,这个问题在国内用的比较少,而国外的受数字保护的音乐和视频,需要额外的获取证书等。
9. 重试次数,对于一个文件可能在本次网络传输中受到问题,尤其是移动网络,所以可以设置一定的重试次数,让任务单独的走下去。
10. 线程开发方式,这里如果你的Java基础比较好,推荐直接使用Java并发库API比较好,如果过去只做过Java开发使用Thread即可,如果Java技术不过关可以Android封装的AsyncTask。
有关完善的多点续传的示例,Android123将在近期提供源码。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------一下内容转自:http://hi.baidu.com/lfcaolibin/blog/item/1516f1f248b733c00a46e0c7.html
实现断点续传的两种思路