断点续传就是从文件上次中断的地方开始重新下载或上传数据,而不是从文件开头。(本文的断点续传仅涉及下载,上传不在讨论之内)当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会去重头下载,这样很浪费时间。所以项目中要实现大文件下载,断点续传功能就必不可少了。当然,断点续传有一种特殊的情况,就是 iOS 应用被用户 kill 掉或者应用 crash,要实现应用重启之后的断点续传。这种特殊情况是本文要解决的问题。
为什么不用AFNetworking?
看了一下源码,AFNetwoking下载任务中接收到的数据是保存在NSMutableData中的。在下载小文件的情况下还好,但如果下载的是大文件,势必会对内存造成很大负担,甚至可能造成程序被杀死。
由于这个原因AFNetworking pass。
断点续传原理
要实现断点续传 , 服务器必须支持。目前最常见的是两种方式:FTP 和 HTTP。下面来简单介绍 HTTP 断点续传的原理。
HTTP
通过 HTTP,可以非常方便的实现断点续传。断点续传主要依赖于 HTTP 头部定义的 Range 来完成。具体 Range 的说明参见 RFC2616中 14.35.2 节,在请求某范围内的资源时,可以更有效地对大资源发出请求或从传输错误中恢复下载。有了 Range,应用可以通过 HTTP 请求曾经获取失败的资源的某一个返回或者是部分,来恢复下载该资源。当然并不是所有的服务器都支持 Range,但大多数服务器是可以的。Range 是以字节计算的,请求的时候不必给出结尾字节数,因为请求方并不一定知道资源的大小。Range 的定义如图 1 所示:
图1.HTTP-Range
图2.展示了HTTP request的头部信息
上面例子中的“Range bytes=6986541-”表示请求资源开头6986541之后的部分。
图3.展示了HTTP response的头部信息:
上面例子中的”Accept-Ranges:bytes”表示服务器接受请求资源的某一个范围,并允许对指定资源进行字节类型的访问。”Content-Range:bytes 6986541-137477478/137477479"说明返回了提供请求资源所在的原始实体内的位置,还给出了整个资源的长度。这里需要注意的是HTTP return code是206而不是200。
实现自己的断点续传
我自己的断点续传是基于NSUrlSession实现的,源码的实现参考了AFNetworking中AFURLSessionManager。断点续传最重要的就下载过程中数据的保存。保存好了数据下次启动时就可以通过保存的数据设置range,进行续传。
1.在HTTP的Header中定义range
2.下载过程中数据的保存。这里使用文件流保存下载过程中的数据。在接收到响应的时候打开文件流。接收到数据时持续将文件写入文件流。最后结束时关闭文件流。
网友评论