1. 程式人生 > >IOS 下載檔案斷點續傳原理與實現(附原始碼)

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來定義頭部域

[cpp] view plain copy  print?
  1. NSURL *url1=[NSURL URLWithString:@"下載地址";  
  2. NSMutableURLRequest* request1=[NSMutableURLRequest requestWithURL:url1];  
  3. [request1 setValue:@"bytes=20000-" forHTTPHeaderField:@"Range"];   
  4. [request1 setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];  
  5. NSData *returnData1 = [NSURLConnection sendSynchronousRequest:request1 returningResponse:nil error:nil];   
  6. [self writeToFile:returnData1 fileName:@"SOMEPATH"];  
  7. -(void)writeToFile:(NSData *)data fileName:(NSString *) fileName  
  8. {  
  9.     NSString *filePath=[NSString stringWithFormat:@"%@",fileName];  
  10.     if([[NSFileManager defaultManager] fileExistsAtPath:filePath] == NO){  
  11.         NSLog(@"file not exist,create it...");  
  12.         [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];  
  13.     }else {  
  14.     NSLog(@"file exist!!!");  
  15.     }  
  16.     FILE *file = fopen([fileName UTF8String], [@"ab+" UTF8String]);  
  17.     if(file != NULL){  
  18.         fseek(file, 0, SEEK_END);  
  19.     }  
  20.     int readSize = [data length];  
  21.     fwrite((constvoid *)[data bytes], readSize, 1, file);  
  22.     fclose(file);  
  23. }  
git程式碼連線: