IOS 下载文件断点续传原理与实现(附源码) 文件断点续传原理与实现...
在网络状况不好的情况下,对于文件的传输,我们希望能够支持可以每次传部分数据。首先从文件传输协议FTP和TFTP开始分析,
FTP是基于TCP的,一般情况下建立两个连接,一个负责指令,一个负责数据;而TFTP是基于UDP的,由于UDP传输是不可靠的,虽然传输速度很快,但对于普通的文件像PDF这种,少了一个字节都不行。本次以IM中的文件下载场景为例,解析基于TCP的文件断点续传的原理,并用代码实现。
什么是断点续传?
断点续传其实正如字面意思,就是在下载的断开点继续开始传输,不用再从头开始。所以理解断点续传的核心后,发现其实和很简单,关键就在于对传输中断点的把握,我就自己的理解画了一个简单的示意图:
原理:
断点续传的关键是断点,所以在制定传输协议的时候要设计好,如上图,我自定义了一个交互协议,每次下载请求都会带上下载的起始点,这样就可以支持从断点下载了,其实HTTP里的断点续传也是这个原理,在HTTP的头里有个可选的字段RANGE,表示下载的范围
下面以IOS 开发为例
NSUrlConnection实现断点续传的关键是自定义http request的头部的range域属性。
Range头域
Range头域可以请求实体的一个或者多个子范围。例如,
表示头500个字节:bytes=0-499
表示第二个500字节:bytes=500-999
表示最后500个字节:bytes=-500
表示500字节以后的范围:bytes=500-
第一个和最后一个字节:bytes=0-0,-1
同时指定几个范围:bytes=500-600,601-999
但是服务器可以忽略此请求头,如果无条件GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是以200(OK)。
在ios中使用NSMutableURLRequest来定义头部域
- NSURL*url1=[NSURLURLWithString:@"下载地址";
- NSMutableURLRequest*request1=[NSMutableURLRequestrequestWithURL:url1];
- [request1setValue:@"bytes=20000-"forHTTPHeaderField:@"Range"];
- [request1setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
- NSData*returnData1=[NSURLConnectionsendSynchronousRequest:request1returningResponse:nilerror:nil];
- [selfwriteToFile:returnData1fileName:@"SOMEPATH"];
- -(void)writeToFile:(NSData*)datafileName:(NSString*)fileName
- {
- NSString*filePath=[NSStringstringWithFormat:@"%@",fileName];
- if([[NSFileManagerdefaultManager]fileExistsAtPath:filePath]==NO){
- NSLog(@"filenotexist,createit...");
- [[NSFileManagerdefaultManager]createFileAtPath:filePathcontents:nilattributes:nil];
- }else{
- NSLog(@"fileexist!!!");
- }
- FILE*file=fopen([fileNameUTF8String],[@"ab+"UTF8String]);
- if(file!=NULL){
- fseek(file,0,SEEK_END);
- }
- intreadSize=[datalength];
- fwrite((constvoid*)[databytes],readSize,1,file);
- fclose(file);
- }
在网络状况不好的情况下,对于文件的传输,我们希望能够支持可以每次传部分数据。首先从文件传输协议FTP和TFTP开始分析,
FTP是基于TCP的,一般情况下建立两个连接,一个负责指令,一个负责数据;而TFTP是基于UDP的,由于UDP传输是不可靠的,虽然传输速度很快,但对于普通的文件像PDF这种,少了一个字节都不行。本次以IM中的文件下载场景为例,解析基于TCP的文件断点续传的原理,并用代码实现。
什么是断点续传?
断点续传其实正如字面意思,就是在下载的断开点继续开始传输,不用再从头开始。所以理解断点续传的核心后,发现其实和很简单,关键就在于对传输中断点的把握,我就自己的理解画了一个简单的示意图:
原理:
断点续传的关键是断点,所以在制定传输协议的时候要设计好,如上图,我自定义了一个交互协议,每次下载请求都会带上下载的起始点,这样就可以支持从断点下载了,其实HTTP里的断点续传也是这个原理,在HTTP的头里有个可选的字段RANGE,表示下载的范围
下面以IOS 开发为例
NSUrlConnection实现断点续传的关键是自定义http request的头部的range域属性。
Range头域
Range头域可以请求实体的一个或者多个子范围。例如,
表示头500个字节:bytes=0-499
表示第二个500字节:bytes=500-999
表示最后500个字节:bytes=-500
表示500字节以后的范围:bytes=500-
第一个和最后一个字节:bytes=0-0,-1
同时指定几个范围:bytes=500-600,601-999
但是服务器可以忽略此请求头,如果无条件GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是以200(OK)。
在ios中使用NSMutableURLRequest来定义头部域
- NSURL*url1=[NSURLURLWithString:@"下载地址";
- NSMutableURLRequest*request1=[NSMutableURLRequestrequestWithURL:url1];
- [request1setValue:@"bytes=20000-"forHTTPHeaderField:@"Range"];
- [request1setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
- NSData*returnData1=[NSURLConnectionsendSynchronousRequest:request1returningResponse:nilerror:nil];
- [selfwriteToFile:returnData1fileName:@"SOMEPATH"];
- -(void)writeToFile:(NSData*)datafileName:(NSString*)fileName
- {
- NSString*filePath=[NSStringstringWithFormat:@"%@",fileName];
- if([[NSFileManagerdefaultManager]fileExistsAtPath:filePath]==NO){
- NSLog(@"filenotexist,createit...");
- [[NSFileManagerdefaultManager]createFileAtPath:filePathcontents:nilattributes:nil];
- }else{
- NSLog(@"fileexist!!!");
- }
- FILE*file=fopen([fileNameUTF8String],[@"ab+"UTF8String]);
- if(file!=NULL){
- fseek(file,0,SEEK_END);
- }
- intreadSize=[datalength];
- fwrite((constvoid*)[databytes],readSize,1,file);
- fclose(file);
- }