常見下載方式之BT下載實現過程詳解

dianliang01發表於2018-11-28


一、 BT 下載是怎麼來的?

在網際網路上下載檔案的方式大概有這麼幾種: FTP HTTP BT eMule( 電驢 ) 等, 瀏覽器會直接支援 FTP HTTP 下載, BT eMule 下載一般需要專用的下載軟體的支援。


接下來分別簡單介紹一下它們的區別:


FTP  File Transfer Protocol (檔案傳輸協議)的英文簡稱,顧名思義,就是提供檔案傳輸的一個協議。首先需要有一個 FTP Server ,負責檔案的儲存並接受網路請求( FTP 連線和指令)提供下載,然後 FTP Client FTP Server 發起網路請求,並將接受到的檔案內容儲存到本地。


HTTP HyperText Transfer Protocol (超文字傳輸協議)的英文簡稱,超文字就是我們平時所說的網頁,透過網頁上的連結把眾多的網頁組織成一個超級大的資訊節點網路,所以叫超級文字。檔案下載只是 HTTP 協議所支援的一個子功能,同樣需要 HTTP Server Nginx Apache IIS 等)和 HTTP Client (各種瀏覽器)來完成檔案的下載。

對以上兩種下載方式做一個簡單總結:

HTTP 下載 1

 

如果使用者想要更快的下載速度呢?


一種選擇是, Client 使用多執行緒下載,搶佔更多的伺服器資源(早期的網際快車 FlashGet 就是這種方式)。

如果使用者量很大,這樣無疑對 Server 造成很大的壓力。然後呢, Server 提供商(網站方)需要提供更多的伺服器和更高的頻寬,但是這需要花很多錢。

 

那麼,有沒有更低成本的解決方案呢?接下來就出現了 BT 下載。


 BT BitTorrent 的縮寫, Torrent 是激流、洪流的意思, Bit 洪流,看名字就很牛的樣子。和以上兩種下載方式最大的區別就是使用者不再直接從伺服器下載檔案,而是使用者之間相互下載,這種方式叫做 P2P Peer to Peer 點對點)。從下圖我們可以看出參與的人越多,下載速度越快


P2P 下載 1

 

二、 BitTorrent P2P 下載是怎麼做到的?

 

要做到 P2P 下載首先需要解決如下兩個問題:

 

     1   如何知道哪些 Client 在下載同一個檔案?

 

     2   對某一個檔案,如何做到同時從多個來源進行下載?

 

對於第一個問題的解決方案:


  設計一個 TrackerServer (跟蹤伺服器),每一個 Client 需要去這裡上報自己正在下載的檔案以及自己的 ip 地址和監聽的端


口。新來的 Client 先要連線到 TrackerServer ,根據要下載的檔案查詢當前正在下載這個檔案的 Clients (Peers)


對於第二個問題的解決方法:


  Client TrackerServer 獲取 Peers 後,分別向他們發起連線並詢問當前的下載進度,然後,同時連線多個 Peers 分別下載他


們已完成的檔案片段,最後拼接出完整的檔案。

 

那麼對於下載進度應該如何表達呢?


  因為檔案不是被順序下載的 ( 因為需要從 Peers 同時下載不同的片段 ) ,所以不可以透過當前已完成的位元組數來表示進度。那


麼,最簡單有效的方式就是把檔案分割成相同大小的片段 (Piece) ,片段的大小一般是 2^n ,比如 2^18=256K ,透過已完


Pieces 的序號列表來表示當前的下載進度。



  另外,因為 Pieces 序號是連續的,可以透過 BitMap 的方式表示每個 Piece Index 是否已完成。 Piece Index 所在的 bit 位為 1


表示該 Piece 已經下載完成。



  如果下載任務是一個資料夾 ( 包含很多檔案 ) 可以把這些檔案按照固定的順序連線起來 ( 邏輯上 ) 進行 Pieces 切分。


Client 獲取到 Peers 的完成列表後,就可以將不同的 Pieces 分配到對應的 Peers 進行並行下載,同時將自己已完成的 Pieces


提供給其他 Peers 來下載。

 

互幫互助、互通有無的和諧社會就此開啟了。

 

到目前為止,我們還有幾個關鍵問題沒有解決:

 

1 、怎麼找到待下載檔案的 TrackerServer


2 Peers 對檔案分片的規則是否一致?


3 、在 TrackerServer 上怎麼唯一的標識一個下載任務?


4 、下載來的 Pieces 是否在傳輸過程中出現了錯誤或者被惡意篡改?


為了解釋上面的問題,此處應該有 .torrent 檔案 (BT 種子 ) 出場了。


 BT 種子檔案主要包括如下關鍵資訊:

BT 種子檔案主要資訊 1

我們找一個種子檔案片段來瞧一下:


 

是不是有似曾相識卻又看不懂的感覺呢?這是因為 .torrent 檔案是 bencoding 編碼表示的。


bencoding 編碼是一種物件序列化表示法(功能和 json 是一樣的,但是規則不一樣), bencoding 編碼透過開頭的字元來指定


接下來的物件的型別,規則如下:


'd' 開頭表示是 dict 型別 , 可以理解為 key=>value 的集合, 'e' 表示結束

'l' (小寫字母 L )開頭表示是 list 型別, 'e' 表示結束

'i'   開頭表示是 integer 型別, 'e' 表示結束,可以表示負數

數字 開頭表示 string 型別,數字為 string 的長度,長度與 string 內容以 ':' 分割開

上圖中標註的地方 8:encoding5:UTF-84:infod5:files ,按照這個規則解析後得到

encoding=>UTF-8

info => { files=> …}


至此,總結一下 BT 下載的基本過程 , 聰明的你是否已經瞭解 BT 下載了呢?


BT 種子下載過程 1

 

接下來是對 BT 協議的一些細節描述,對細節感興趣的話可以繼續看一下

 

三、 BT 協議之連線 TrackerServer

 

TrackerServer HTTP UDP 協議兩種,這裡簡單介紹一下 HTTP 協議的 TrackerServer BTClient 透過 HTTP Get 請求完成 Peers 獲取和自身的註冊。請求的 URL 格式如下:

Trackerserver-url?info_hash=xxxxxxxxxxxx,peer_id=xxxxxxxxxxx,ip=x.x.x.x,port=xxxx,uploaded=xx,downloaded=xx,left=xx,event=x

URL 中各引數需要經過 urlencode 處理,各個引數的意義如下:



TrackerServer 的返回內容為經過 bencode Dict 型別,如果返回失敗,會包含 "failure reason" 鍵值,內容為可讀的失敗原因。

"interval":   為向 Trackerserver 發起常規查詢的間隔時間, BTClient 需要按照這個間隔時間定期向 TrackerServer 報告下載狀態,同時獲取最新的 Peers 資訊。

"peers"  : 為一個 Peer List ,每個 Peer 包含以下幾項內容:

"peer id" :   20 位元組的 Peer 自分配 ID

"ip"  : Peer IP 地址

"port" Peer 監聽的埠

抓包得到的一個 TrackerServer 的返回內容 , 經過 bencode 解析後如下:

interval =>1800

 

  peers => [

 

         {

 

ip => 100.197.121.204,

 

peer id => -SD0100-\310\225\2576z\264U\240O\034

 

              port => 14678

 

         }

 

   // 其他 Peer

 

]

 

 

      關於 peers 列表,當前大多數 TrackerServer 支援 compact peers 格式以減少返回內容的長度,該格式下 peers 屬性為一個 String ,每六個位元組為一組,每組表示一個 Peer ,其中前 4 個位元組 表示 PeerIP ,後兩個位元組表示 Peer Port  

四、 BT 協議細節之連線 Peers

Peer 建立 TCP 連線後,首先傳送 HandShake 訊息進行協議基本資訊的交換,協商成功後,緊接著開始送各自的 PiecesBitmap bitfield 訊息)。然後向對端傳送自己缺失的 Pieces 請求( request 訊息),開啟 Pieces 交換下載。

 

Handshake 訊息主要是協商協議名稱、 Info Hash PeerID ,保證對端是相相容的 Peer ,如果資訊協商不上 ( 比如協議名稱不是 BitTorrent Protocol 或者 Info Hash 不一致 ), TCP 連線將被關閉。 HandShake 訊息格式如下:

 

 

HashShake 成功之後就開始透過如下一系列 peer_msg 訊息來完成下載控制, peer_msg 訊息格式如下:



msg_len 4 位元組)

msg_type 1 位元組)

payload (若干位元組)

如果 msg_len 0 , 這表示 KeepAlive 訊息, KeepAlive 用來判斷對端是否仍然存活。

 

訊息型別的取值及作用:


 

如下是一個 request 和一個 piece 訊息:

choke, unchoke, interested, not interested 訊息綜合完成 Peers 的流控策略,以期達到更好的網路吞吐以及維持下載的公平性,一個指導思想是更多的上傳將獲得更多的下載。

 

BTClient 的實現過程中還會涉及到很多的程式設計問題,比如:非同步 socket 操作、多執行緒控制、流量控制、快取策略、下載優先順序、檔案儲存等,這裡就不再一一展開了。

 

注:本文由點量軟體整理自網際網路DolitQin520(V)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31439365/viewspace-2221935/,如需轉載,請註明出處,否則將追究法律責任。

相關文章