HTTP-斷點續傳和多線程下載

HTTP斷點續傳

  Range:客戶端發請求的範圍

  Content-Range:服務端返回當前請求範圍和文件總大小

 

   續傳成功返回206 

  文件又變動,返回200和新文件內容

 

 

HTTP1.1 協議(RFC2616)開始支持獲取文件的部分內容,這爲並行下載以及斷點續傳提供了技術支持。它通過在 Header 裏兩個參數實現的,客戶端發請求時對應的是 Range ,服務器端響應時對應的是 Content-Range

 

 

Range

用於請求頭中,指定第一個字節的位置和最後一個字節的位置,一般格式:

 Range:(unit=first byte pos)-[last byte pos]

 

1.以下幾點需要注意:

(1)這個數據區間是個閉合區間,起始值是0,所以“Range: bytes=0-1”這樣一個請求實際上是在請求開頭的2個字節。

(2)“Range: bytes=-200”,它不是表示請求文件開始位置的201個字節,而是表示要請求文件結尾處的200個字節。

(3)如果last byte pos小於first byte pos,那麼這個Range請求就是無效請求server需要忽略這個Range請求,然後迴應一個200,把整個文件發給client。

(4)如果last byte pos大於等於文件長度,那麼這個Range請求被認爲是不能滿足的,server需要迴應一個416,Requested range not satisfiable。

 

2.示例解釋:

 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 表示第一個和最後一個字節 

Range: bytes=500-600,601-999 同時指定幾個範圍

 

 

Content-Range

用於響應頭中,在發出帶 Range 的請求後,服務器會在 Content-Range 頭部返回當前接受的範圍和文件總大小一般格式:

 

Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]

 

例如:

 請求下載整個文件: 

 

GET /test.rar HTTP/1.1 

Connection: close 

Host: 116.1.219.219 

Range: bytes=0-801   //一般請求下載整個文件是bytes=0- 或不用這個頭

 

一般正常回應 

 

HTTP/1.1 200 OK 

Content-Length: 801      

Content-Type: application/octet-stream 

Content-Range: bytes 0-800/801   //801:文件總大小

 

而在響應完成後,返回的響應頭內容也不同:

HTTP/1.1 200 Ok(不使用斷點續傳方式) 

HTTP/1.1 206 Partial Content(使用斷點續傳方式)

 

 

總結:

 

HTTP1.1協議(RFC2616)中定義了斷點續傳相關的HTTP頭 Range和Content-Range字段,一個最簡單的斷點續傳實現大概如下: 

  1.客戶端下載一個1024K的文件,已經下載了其中512K 

  2. 網絡中斷,客戶端請求續傳,因此需要在HTTP頭中申明本次需要續傳的片段: 

       Range:bytes=512000- 

    這個頭通知服務端從文件的512K位置開始傳輸文件 

  3. 服務端收到斷點續傳請求,從文件的512K位置開始傳輸,並且在HTTP頭中增加: 

    Content-Range:bytes 512000-/1024000 

    並且此時服務端返回的HTTP狀態碼應該是206,而不是200。 

 

但是在實際場景中,會出現一種情況,即在終端發起續傳請求時,URL對應的文件內容在服務端已經發生變化,此時續傳的數據肯定是錯誤的。如何解決這個問題了?顯然此時我們需要有一個標識文件唯一性的方法。在RFC2616中也有相應的定義,比如實現Last-Modified來標識文件的最後修改時間,這樣即可判斷出續傳文件時是否已經發生過改動。同時RFC2616中還定義有一個ETag的頭,可以使用ETag頭來放置文件的唯一標識,比如文件的MD5值。

 

終端在發起續傳請求時應該在HTTP頭中申明If-Match 或者If-Modified-Since 字段,幫助服務端判別文件變化。 

 

另外RFC2616中同時定義有一個If-Range頭,終端如果在續傳是使用If-Range。If-Range中的內容可以爲最初收到的ETag頭或者是Last-Modfied中的最後修改時候。服務端在收到續傳請求時,通過If-Range中的內容進行校驗,校驗一致時返回206的續傳回應,不一致時服務端則返回200迴應,迴應的內容爲新的文件的全部數據。

 

===========================================================

多線程下載:

假設你要開發一個多線程下載工具,你會自然的想到把文件分割成多個部分,比如4個部分,然後創建4個線程,每個線程負責下載一個部分如果文件大小爲403個byte,那麼你的分割方式可以爲:0-99 (前100個字節),100-199(第二個100字節),200-299(第三個100字節),300-402(最後103個字節)。

分割完成,每個線程都明白自己的任務,比如線程3的任務是負責下載200-299這部分文件,現在的問題是:線程3發送一個什麼樣的請求報文,才能夠保證只請求文件的200-299字節,而不會干擾其他線程的任務。這時,我們可以使用HTTP1.1的Range頭。Range頭域可以請求實體的一個或者多個子範圍,Range的值爲0表示第一個字節,也就是Range計算字節數是從0開始的:

    

表示頭500個字節:Range: bytes=0-499

    表示第二個500字節:Range: bytes=500-999

    表示最後500個字節:Range: bytes=-500

    表示500字節以後的範圍:Range: bytes=500-

    第一個和最後一個字節:Range: bytes=0-0,-1

    同時指定幾個範圍:Range: bytes=500-600,601-999

所以,線程3發送的請求報文必須有這一行:

Range: bytes=200-299

 

服務器接收到線程3的請求報文,發現這是一個帶有Range頭的GET請求,如果一切正常,服務器的響應報文會有下面這行:

HTTP/1.1 206 OK

表示處理請求成功,響應報文還有這一行

Content-Range: bytes 200-299/403

斜槓後面的403表示文件的大小,通常Content-Range的用法爲:

 . The first 500 bytes:

 Content-Range: bytes 0-499/1234

 

 . The second 500 bytes:

 Content-Range: bytes 500-999/1234

 

 . All except for the first 500 bytes:

 Content-Range: bytes 500-1233/1234

 

 . The last 500 bytes:

 Content-Range: bytes 734-1233/1234

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章