跳至內容

BitTorrent協議規範

來自維基學院

BitTorrent是由布萊姆·科恩設計的一個點對點(P2P)文件共享協議,此協議使多個客戶端通過不可信任的網絡的文件傳輸變得更容易。

此規範的目的是詳細介紹 BitTorrent 協議規範 v1.0 。Bram 的協議規範網站 http://www.bittorrent.com/protocol.html[失效連結] 簡要地敘述了此協議,在部分範圍缺少詳細行為闡述。希望此文檔能成為 一個正式的規範,明確的條款,將來能作為討論和執行的基礎。

此文檔規定由 BitTorrent 開發者維持和使用。歡迎大家為它做貢獻,其中的內容代表當前協議,它仍由許多客戶使用。

這裡不是提出特性請求的地方。如果有請求,請見郵箱列表。

應用範圍

[編輯 | 編輯原始碼]

本文檔適用於 BitTorrent 協議規範的第一版(v1.0)。目前,這份文檔應用於 torrent 文件結構、用戶線路協議和服務器(Tracker)HTTP/HTTPS 協議規範。如果某個協議有了新的修訂,請到對應頁面查看,而不在這裡。

在本文檔中,使用了許多約定來簡明和明確地表達信息。

  • 用戶(peer)v/s 客戶端(client):在本文檔中,一個用戶可以是任何參與下載的 BitTorrent 客戶端。客戶端也是一個用戶,儘管 BitTorrent 客戶端運行在本地機器上。本規範的讀者可能會認為自己是連接了許多用戶的客戶端。
  • 片斷(piece)v/s 塊(block):在本文檔中,片斷是指在元信息文件中描述的一部分已下載的數據,它可通過 SHA-1 hash 來校驗。而塊是指客戶端向用戶請求的一部分數據。兩塊或更多塊組成一個完整的片斷,它能被校驗。
  • 實際標準:大的斜體字文本指出普通的準則在不同客戶端 BitTorrent 的執行,它被當作為實際標準。(對照英文原文,common應該翻譯成通用或者常見,這句話的大概意思是一個規範由於被許多不同的BitTorrent客戶端實現所通用,以至於被當做是實際標準)

為了幫助其他人找到本文檔最近的修改,請填寫改變日誌(最後一段)。它應包含一個簡短的項目(如:一行),用來記錄你每次對此文檔的主要改動。

B編碼是一種以簡潔格式指定和組織數據的方法。支持下列類型:字節串、整數、表和字典。

字節串

[編輯 | 編輯原始碼]

字節串按如下編碼:<以十進制 ASCII 編碼的串長度>:<串數據>
注意沒有開始和結束的分隔符。 例:「4:spam」 代表字符串「spam」

整數按如下編碼:i<以十進制 ASCII 編碼的整數>e
開始的「i」與結尾的「e」分別是開始和結束分隔符。可以使用如「i-3e」之類的負數。但不能把「0」放到數字的前面,如「i04e」。另外,「i0e」是有效的。
例:「i3e」代表整數「3」

表按如下編碼:l<編碼值>e
開始的「l」與結尾的「e」分別是開始和結束分隔符。 表可以包含任何已編碼的類型,包括整數、串、字典和其他的表。
例:l4:spam4:eggse 代表兩個串的表「spam」、「eggs」

字典按如下編碼:d<編碼串><編碼元素>e
開始的「d」與結尾的「e」分別是開始和結束分隔符。 注意關鍵字必須被編碼為串。值可以是任何已編碼類型,包括整數、串、表和其他字典。關鍵字必須是串,以分類的順序出現(以原始串排列,而不是以字母數字)
例1:d3:cow3:moo4:spam4:eggse 代表字典 { "cow" => "moo", "spam" => "eggs" }
例2:d4:spaml1:a1:bee 代表字典 { "spam" => ["a", "b"] }

元信息文件結構

[編輯 | 編輯原始碼]

所有在元信息文件中的數據都要編碼。編碼規則如上所述。

元信息文件(以 .torrent 結尾的文件)的內容是一個編碼的字典,包含以下列表中的各項。所有字符串值都以 UTF-8 編碼。沒有「可選」標記的鍵值是必需的字段:

  • 信息

一個描述 torrent 文件的字典。有兩種可能的形式:一種是沒有目錄結構的「單一文件」,另一種是包含子目錄樹的「多文件」

對於「單一文件」來說,信息字典包含以下的結構:

長度:文件字節數長度(整數)

md5和:(可選)一個 32 位的 16 進制字符串,它對應於文件的 MD5和。不被 BitTorrent 所使用,但被一些程序包含,以提供更大的兼容性。

名稱:文件的名稱。建議使用(字節串)。

片斷長度:每個片斷的字節數(整數)。

片斷:包含所有 20 字節 SHA-1 散列值的字符串,每個片斷都有唯一的值。(字節串)

對於「多文件」來說,信息字典包含以下的結構:

文件:字典列表,每個文件都有一個。每個在表中的字典包含以下鍵值:

長度:文件長度的字節數(整數)

md5和:(可選)一個 32 位的 16 進制字符串,它對應於文件的 MD5和。不被 BitTorrent 所使用,但被一些程序包含,以提供更大的兼容性。

路徑:一個包含着一個或多個字符串元素的,它包含路徑和文件名。每個表中元素對應於一個目錄名或(在最後的元素的情況下)文件名。
例:文件名「dir1/dir2/file.ext」將包含三種串元素:「dir1」、「dir2」和「file.ext」。編碼為串表的例子「l4:dir14:dir28:file.exte」

名稱:結構中根目錄的名稱——包含上述文件列表中所有文件的目錄(字符串)

片斷長度:每個片斷的字節數(整數)。

片斷:包含所有 20 字節 SHA-1 散列值的字符串,每個片斷都有唯一的值。(字節串)

  • 發布:服務器的發布 URL(字符串)
  • 創建日期:(可選)torrent 文件的創建時間,使用標準 Unix 時間格式(從 UTC 1970年1月1日 00:00:00 開始,整數秒)
  • 評論:(可選)發布者的自由評論(字符串)
  • 由……創建:(可選)創建 torrent 文件的名字和程序版本(字符串)

注意:

  • 片斷長度指定了標準的片斷大小,通常是 2 的 n 次方。片斷長度的一般是根據 torrent 文件中所有數據的數量來決定的,如果片斷太大,會導致效率低,出錯概率增加;而如果太小,則會使生成的 torrent 元數據文件過大。常識決定使用最小的片斷大小,這樣就會使生成的 torrent 文件不大於 50-75 KB(可以減輕存儲 torrent 文件服務器的負擔)。但是,由於沒有嚴格限制存儲和帶寬,即使為了高效率的共享文件可能導致生成更大的 torrent 文件,也建議將小於 8-10 GB 文件的片斷大小設為小於或等於 512 KB。通常大小是 256 KB,512 KB 和 1 MB。除了最後的片斷大小不定以外,其餘片斷大小是相等的。因此片斷的數目由總大小決定。對於多文件模式下的片斷邊界,將文件數據設想為一個長的連續流,由文件有序列表中的每個文件相互連接而成。片斷數目和其邊界的決定方式與單一文件相同。片斷可能由兩個文件的邊界組成。
  • 每個片斷都有相應的 SHA-1 hash 數據校驗碼。這些校驗碼相互連接形成上述的信息字典的片斷值。注意這不是一個表,而是一個字符串。其長度必須是 20 字節的整數倍。

服務器 HTTP/HTTPS 協議

[編輯 | 編輯原始碼]

服務器是用類響應 HTTP GET 請求的一種 HTTP/HTTPS 服務。該請求包括客戶端的度量標準,這個標準可以幫助服務器全面統計 torrent 文件。基本的 URL 包括元數據文件(torrent)中定義的「發布 URL」。再將那些參數通過標準 CGI 方法添加到此 URL 中(如:「?」在發布 URL 之後,緊接着「參數=值」的序列,分隔符「&」)

注意所有在 URL 中的二進制數據(特別是 info_hash 和 peer_id)必須使用轉義符。這意味着除 0-9,a-z,A-Z和$-_.+!*'()外,其餘字節需要採用「%nn」格式的編碼,其中的「nn」是字節的 16 進制數值。(詳細見 RFC1738

客戶端向服務器的 GET 請求的參數如下:

  • info_hash:元信息文件中 20 字節的 SHA-1 散列值。注意此值會進入編碼字典中,如上述的信息關鍵字的定義所述。與不需編碼的 peer_id 相比,它總是被 URL 編碼。
  • peer_id:客戶端 ID ,客戶端用來唯一標識自己 ID 的 20 字節的串,它在客戶端啟動時生成。允許為任何值,包括二進制數據。目前沒有特定的算法來生成客戶端 ID。但是,人們會認為它至少對於自己的本地機器是唯一的,從而應該像進程 ID 一樣合併數據,也可能在啟動時由時標記錄。見本區域下面的一般客戶端編碼的 peer_id。
  • 端口:客戶端監聽的端口號。BitTorrent 所使用的典型端口是 6881-6889。如果此範圍的端口都無效,可以選擇其他的。
  • 已上傳的:從客戶端發送「已開始」事件到服務器算起的上傳總量,數值採用 10 進制的 ASCII。對於沒有在官方規範明確指出的,該值應為已上傳的字節總數。
  • 已下載的:從客戶端發送「已開始」事件到服務器算起的下載總量,數值採用 10 進制的 ASCII。對於沒有在官方規範明確指出的,該值應為已下載的字節總數。
  • 剩下的:客戶端需要下載的字節數,以 10 進制 ASCII 編碼。
  • 緊密的:客戶端接受一個緊密的響應。客戶端列表由客戶端串代替,此串中每個客戶端都編碼成 6 字節。前 4 字節是主機名(以網絡的字節順序),後兩個字節是端口號(同樣以網絡字節的順序)。
  • 事件:如果被指定,則是已開始已完成已停止中的一個,或者為空(表示未指定)。如果未指定,此請求為常規時間間隔中的一次運行。
    • 已開始:向服務器發送的第一個請求,必須包含開始值的事件關鍵字。
    • 已停止:如果客戶端關機則鬚髮送到服務器上。
    • 已完成:完成下載時必須發送到服務器上。但是,當客戶端啟動時下載完成度為 100%(即:做種中)則不會發送。可能這是允許服務器增加「已完成下載」的方法。
  • ip:可選。客戶端的真實 IP 地址,以點分四元組格式或 RFC3513 中定義的 16 進制 IPv6 地址。注意:大體上此參數沒有客戶端地址重要,它能由 IP 地址決定,HTTP 請求也來自該處。僅在請求參與的 IP 地址不是客戶端的 IP 地址的情況下才需要。這種情況發生在客戶端通過代理服務器與服務器進行通信的情形。當客戶端和服務器同時處在本地 NAT 網關時也需要。原因是服務器會發出客戶端的內部地址(RFC1918),這是不可到達的。所以客戶端必須清楚地把自己的外部可到達的 IP 地址發送到其他客戶端中。不同的服務器對此參數的解釋有所不同。某些只有當請求參與的 IP 地址屬於 RFC1918 時才允許。有些無條件允許,但有些則完全忽略。如果使用 IPv6 地址(如:2001:db8:1:2::100),則表示客戶端能通過 IPv6 進行通信。
  • 需求數目:可選。客戶端想從服務器接收的用戶數目。允許此值為「0」。如果不用此項,則默認值為 50 個用戶。
  • 關鍵字:可選。一個不與任何用戶共享的另外的標識。當 IP 地址改變後,允許客戶端證明它們的標識。
  • 服務器id:可選。如果先前發布包含服務器的 id,它應放在這裡。

服務器作出「text/plain」文檔的響應包括以下編碼字典的關鍵字:

  • 失敗原因:如果當前使用此值,則其餘關鍵字不會使用。該值是可讀的錯誤消息,包括請求失敗的原因。(字符串)
  • 警告消息:(新)與失敗原因相似,但響應仍然會被正常處理。警告消息看起來像錯誤。
  • 時間間隔:以秒計算,是客戶端發送規則請求到服務器之後等待的時間。(強制)
  • 最小時間間隔:最小發布時間間隔。當前客戶重發間隔不能小於此值。
  • 服務器 id:一個客戶端應在下一個通告發回的字符串。如果沒有該值,先前通告會發出一個服務器 id ,不要丟棄舊的值,一直使用它。
  • 完成:擁有完整文件的用戶數,即做種者(整數)
  • 未完成:非種子用戶的數目,也叫「吸血者」(整數)
  • 用戶:是字典的列表,每個值都有如下的關鍵字:
    • 用戶 id:用戶的自選擇 ID,如上述用來發送服務器請求的(字符串)
    • ip:用戶的 IP 地址(IPv4 或 IPv6 格式)或域名(字符串)
    • 端口:用戶的端口號(整數)

如上所述,用戶列表長度默認值為 50。如果連接的用戶少於該值,列表會更小。另外,服務器隨機選擇用戶及其響應。服務器在響應請求時可能使用一個更智能的機構來選擇用戶。例如,應避免向其他做種者報告種子。

在事件發生(即:已停止或已完成)或客戶端需要連接更多的用戶時,客戶端向服務器發送請求的間隔可以低於指定的時間間隔。但是,為了獲得更多的用戶而向服務器頻繁地請求會被認為是錯誤的行為。如果客戶端想在回應中得到許多用戶,則需要在「需求數目」參數中設定。

使用者注意:30 個用戶就算豐富的源了,官方客戶端版本 3(v3)實際上在連接數少於 30 時會嘗試增加新的連接,當連接數大於或等於 55 時會拒絕連接多餘的用戶。這個值對性能很重要。當完成下載一個新的片斷時,「已擁有」消息(見下面)將會發送到最活動的用戶。結果廣播通信量與用戶數目成正比例增加。大於 25 時,新用戶不太可能會增加下載速度。有人強烈建議用戶界面設計者使該項模糊和很難修改,因為那樣做幾乎沒有用。

服務器「刮」約定

[編輯 | 編輯原始碼]

根據慣例,多數服務器支持請求的另一種形式,這種方式詢問給定的服務器正在處理的 torrent(或所有的 torrent)。通常叫做「刮頁」,因為它自動處理「刮屏」(服務器統計頁)冗長的部分。刮 URL 也是一種類似於上面描述的 HTTP GET 方法。但基本 URL 不同。用以下步驟來得到刮 URL:從發布 URL 開始尋找其中最後一個「/」。如果在文本之後的「/」不是「announce」,它將被作為一個符號,此符號不支持刮約定。如果是,則以「scrape」代替「announce」來找到刮頁。

例:(發布 URL -> 刮 URL)

 http://example.com/announce          -> http://example.com/scrape
 http://example.com/x/announce        -> http://example.com/x/scrape
 http://example.com/announce.php      -> http://example.com/scrape.php
 http://example.com/a                 -> (不支持刮)
 http://example.com/announce?x=2%0644 -> http://example.com/scrape?x=2%0644
 http://example.com/announce?x=2/4    -> (不支持刮)
 http://example.com/x%064announce     -> (不支持刮)

特別注意:結束引語沒有完成。此標準是由 Bram 在 BitTorrent 開發列表文件中說明的。

刮 URL 可以作為可選參數「info_hash」的一個補充,是一個 20 字節的值。這限制了服務器向特殊種子匯報。另外,服務器正在處理的所有種子的統計也被發回。為了降低服務器的負載和帶寬,有人強烈建議軟件作者儘可能使用「info_hash」參數。

HTTP GET 方法的響應是一個由編碼字典組成的「text/plain」文檔,包括以下關鍵字:

  • 文件:每個 torrent 都包含一對關鍵字的字典,內容是統計數據。如果添加了有效的「info_hash」,此字典將包含單個關鍵字。每個關鍵字由一個 20 字節的 info_hash 值組成。該關鍵字的值是另一個包含下列名稱的嵌套字典:
    • 已完成:擁有整個文件的用戶數目,即做種者(整數)
    • 已下載:服務器註冊編號完成的總數(「事件=完成」,即客戶端完成下載 torrent)
    • 未完成:非做種者用戶的數目,也叫「吸血者」(整數)
    • 名稱:(可選)torrent 的內部名稱,由 torrent 文件中信息字段指定

注意此響應有三層字典嵌套。例如:

d5:filesd20:....................d8:completei5e10:downloadedi50e10:incompletei10eeee

其中「....................」是 20 字節的 info_hash,以上表明有 5 個做種者,10 個吸血者和 50 個完成下載的用戶。

用戶線路協議(TCP)

[編輯 | 編輯原始碼]

用戶線路協議使元信息文件中片斷的交換變得更容易。

注意原始規範在描述用戶協議時也使用術語「片斷」,但與元信息文件中的術語「片斷」不同。由於該原因,術語「塊」將在本規範中用來描述用戶之間通過線路交換的數據。

客戶端必須為每個遠程用戶的連接保持狀態信息:

  • 被阻塞:遠程用戶是否阻塞此客戶端。當用戶阻塞客戶端時,不會響應任何請求。客戶端不應嘗試發送請求塊,所有未響應的請求會被遠程用戶丟棄。
  • 感興趣: 遠程用戶是否對此客戶端感興趣。當客戶端未阻塞時,遠程用戶將開始發送請求塊。

注意這也意味着客戶端需要記住自己是否對遠程用戶感興趣和阻塞它。因此,真正的列表看起來像這樣:

  • am_choking:此客戶端阻塞遠程用戶
  • am_interseted:此客戶端對遠程用戶感興趣
  • peer_choking:遠程用戶阻塞此客戶端
  • peer_interested:遠程用戶對此客戶端感興趣

客戶端的連接以「被阻塞」和「不感興趣」開始。也就是:

  • am_choking = 1
  • am_interested = 0
  • peer_choking = 1
  • peer_interested = 0

當客戶端對遠程用戶感興趣並且遠程用戶未阻塞該客戶端時,客戶端開始下載塊。當客戶端沒有阻塞遠程用戶並且遠程用戶對該客戶端感興趣時,客戶端開始上傳塊。

客戶端保持通知遠程用戶自己是否對它們感興趣,這是很重要的。與每個遠程用戶連接的狀態信息應保持最新,直到該客戶端被阻塞。這允許遠程用戶知道當自己未阻塞時,客戶端是否會開始下載;反之亦然。

數據類型

[編輯 | 編輯原始碼]

如果不特別指定,在用戶線路協議中的所有整數都會編碼成 4 字節 big endian 值。這包括所有消息中的長前綴,它在握手之後。

消息流

[編輯 | 編輯原始碼]

用戶線路協議包括初始握手。之後,用戶通過長前綴消息的交換來進行通信。長前綴是上述的一個整數。

握手是必需的消息,它一定是由客戶端發送的第一條消息。

  • 握手:<pstrlen><pstr><reserved><info_hash><peer_id>
    • pstrlen:<pstr>串的長度,作為單個原始字節
    • pstr:協議的串標識符
    • reserved:8 個保留字節。當前的執行使用全〇。字節中的每位可以用來改變協議的行為。一封 Bram 的電子郵件建議首先使用末位,以使首位可用來改變末位的含義。
    • info_hash:元信息文件信息關鍵字的 20 字節 SHA-1 散列值。這與服務器請求中發送的 info_hash 意義相同。
    • peer_id:每個客戶端用來作為唯一標識的 20 個字節的串。這與服務器請求中發送的 peer_id 意義相同。

在 BitTorrent 協議 v1.0 中:pstrlen=19,pstr="BitTorrent protocol"

連接的發起者應該立即發送彼此的握手信息。即使接收者能同時提供多個 torrent(torrent 通過自己的 info_hash 來唯一標識),它也應等待發起者的握手信息。但是,接收者在看到握手的 info_hash 部分後必須迅速回應。服務器的 NAT 檢查特性不會發送握手的 peer_id 字段。

如果客戶端收到一個當前不能處理的握手 info_hash,該客戶端就會斷開那個連接。

如果連接的發起者收到一個握手信息,其中的 peer_id 與預期的不同,那麼發起者就會斷開該連接。注意發起者可能會收到來自服務器的遠程用戶信息,它包括遠程用戶註冊的 peer_id。來自服務器的 peer_id 與握手信息中的應該相同。

主要有兩種將客戶端及其版本信息編碼到 peer_id 的方法:Azureus 型和 Shadow 型。

Azureus 型使用如下編碼:「-」,一個客戶端標識使用兩個字符,版本號用 4 個 ASCII 數字表示,「-」緊跟在隨機數字之後。

例如:'-AZ2060-'...

已知採用這種方法編碼的客戶端是:

Shadow 型採用如下編碼:用 1 個 ASCII 字母或數字標識客戶端,3 個 ASCII 數字標識版本號,「——」緊跟在隨機數字之後。

例如:'S587——'...

已知採用此種類型編碼的客戶端為:

Bram 的客戶端現在採用的形式: 'M3-4-2--'

BitComet則不同。它的 peer_id 由四個 ASCII 字符組成「exbc」,後面是兩個字節的「x」和「y」,之後才是隨機字符。版本號「x」是在小數點前的十進制數值,「y」是小數點之後的兩個十進制數值。BitLord 使用相同的結構,但在版本號後添加「LORD」字符。一個 BitComet 的非官方補丁將「exbc」替換成了「FUTB」。BitComet 用戶標識的編碼在 0.59 及其以前的版本都採用的 Azureus 型。

XBT Client也有自己的風格。其 peer_id 由三個大寫字母「XBT」緊跟三個代表版本號的 ASCII 數字。如果客戶端處在調試階段,第七字節則是小寫字母「d」,其他情況下是「-」。之後是「-」和隨機數字,大寫和小寫字母。例:'XBT054d-'表示 0.5.4 版的開始調試階段。

Opera 8 previews採用以下結構:前面兩個字符「OP」緊跟四個相等的構建號。之後所有字符都是隨機小寫 16 進制的數字。

Bits on Wheels採用格式「-BOWAxx-yyyyyyyyyyyy」,其中「y」是隨機大寫字母,x 取決於版本。版本 1.0.6 中 xx=0C。

許多客戶端使用隨機數字或 12 個〇緊跟着隨機數字(如以前舊版本的 Bram 客戶端)。

協議中所有發送的消息均採用「<長前綴><消息標識符><有效負載>」的形式。長前綴是一個 4 字節 big endian 值。消息標識符是一個十進制字符。有效負載是消息依賴的。

keep-alive: <len=0000>

「保持活動」消息是由〇組成的字節串,將長前綴設為〇可指定。沒有消息標識符和有效負載。如果在一段時間內,用戶沒有收到消息,它會斷開連接,所以需要發送活動消息來維持連接。一條保持活動消息大概每兩分鐘發送一次。

choke: <len=0001><id=0>

阻塞消息是定長的,無有效負載。

unchoke: <len=0001><id=1>

未阻塞消息是定長的,無有效負載。

interested: <len=0001><id=2>

感興趣消息是定長的,無有效負載。

not interested: <len=0001><id=3>

不感興趣消息是定長的,無有效負載。

have: <len=0005><id=4><piece index>

擁有消息是定長的。有效負載是剛成功下載和通過散列值校驗的〇基片段的索引。

使用者注意:這是嚴格的定義,實際上會用到某些遊戲程序。特別地,因為用戶極不可能下載已經擁有的片斷,用戶可能不會選擇向另一個用戶宣布已擁有那個片斷的消息。少量「擁有抑制」會導致擁有消息減少一半,在協議前面將轉化到 25-35%。

惡意用戶可能會選擇宣布擁有別人永遠不會下載的片斷。因此,向普通用戶發送此信息是壞主意。

bitfield: <len=0001+X><id=5><bitfield>

位字段消息可能在握手序列發送完成後,在其他任何消息發送之前立即發送。它是可選的,如果客戶端沒有此片斷則不必發送。

位字段消息是變長的,其中的「X」是位字段的長度。有效負載是代表成功下載片斷的位字段。首字節的高位對應片斷索引 0。已清除的位則指出缺少的片斷,通過一個有效可用的片斷來設置位。末位剩下的位設置為〇。

一個錯誤長度的位字段被認為是錯誤。客戶端在收到不正確大小的位字段或已有設置為剩下位的位字段時應斷開連接。

request: <len=0013><id=6><索引><開始><長度>

請求消息是定長的,用來請求塊。有效負載包含以下信息:

索引:指定〇基片斷索引的整數。

開始:指定片斷內〇基字節的偏移量整數。

長度:指定被請求長度的整數。

根據官方規範有關主要版本3,「所有當前執行應使用 2^15(32 KB),請求數量大於 2^17(128 KB)時應斷開連接。」在主要版本4中,此反應修改到了 2^14(16 KB),超過該值的用戶會強迫拒絕。注意到塊請求小於片斷大小(>=2^18 字節),所以為下載一個完整片斷需要多次請求。

由於新版本將限制定在 16 KB,嘗試使用 32 KB 的塊就好比用 4 發子彈來玩俄式輪盤——會遇到困難。更小的請求會導致更大的系統時間和空間開銷,因為要跟蹤很多請求。結果應使用所有客戶端都允許的 16 KB。

請求塊大小的限制執行的選擇沒有減少一部分清楚。在主要版本 4 中,強制使用 16 KB 的請求,許多客戶端會使用該值,只有一個嚴格客戶端組不會使用。大多數舊客戶端使用 32 KB 請求,不允許明顯減少可能用戶的批次。同時 16 KB 是現在部分官方的限制(「部分」是因為官方協議文檔沒有更新),所以強制使用沒有錯。另外,允許更大的請求增大了可能用戶的批次,除在非常低的帶寬連接(小於 256 kbps)中,多個塊會在一個阻塞周期內完成下載,從而強迫使用舊的限制僅會降低很少的性能。因此,推薦僅在舊的 128 KB 下才強行限制。

piece: <len=0009+X><id=7><索引><開始><塊>

片斷消息是變長的,其中的「X」是塊長度。有效負載包含以下信息:

索引:由〇基片斷索引指定的整數

開始:由片斷內〇基字節偏移量指定的整數

:數據塊,是索引指定片斷的子集。

cancel: <len=0013><id=8><索引><開始><長度>

取消信息是定長的,用來取消塊的請求。有效負載與「請求」消息相同。典型用在「最後階段」中。(見下面的算法段)

port: <len=0003><id=9><listen-port>

端口消息是由運行 DHT 服務器的新版本的主要部分。監聽端口是用戶 DHT 節點正在監聽的端口。如果 DHT 服務器支持,則應把此用戶加入本地的路由表中。

通常建議用戶在每個連接上保持一些未完成的請求。因為從一塊的下載到開始下載另一塊需要一個完全的往返程(往返程在片斷消息和下一個請求消息之間)。一旦與高 BDP(Bandwidth Delay Product,高延遲或帶寬)相連,會降低很多性能。官方客戶端未完成請求的默認值是 5。

用戶注意:這是最嚴格的性能條款。一個 5 請求的靜態隊列對於具有 50 ms 延遲 5 Mbps 中的 32 KB 塊是合理的。連接更大的帶寬越來越常見,所以用戶界面設計者被催促使其對於改變更適用。特別地,線纜調製解調器以調整通信量和增加其可能緩和部分由此導致的問題,這是眾所周知的。

自動調整:調整此參數的一個合理的方法是連續測量單個連接的帶寬。如果該用戶增加帶寬而隊列不夠,則嘗試增加隊列長度。使用相同標誌如果減少隊列長度沒有減少帶寬和延遲,可能是隊列長度太大了。

超級種子

[編輯 | 編輯原始碼]

(該項不是原始規範的一部分)

在 S-5.5 中的超級種子特性是一種新的做種算法,用來幫助只有有限帶寬的做種者發布很大的文件,減少為了產生新的種子而上傳的數據總量。

當做種者使用「超級種子模式」時,它不會作為標準種子,而是偽裝成一個沒有數據的普通客戶端。當客戶端連接時,它會通知它們自己收到一塊從未發送或源很少的片斷。這將促使客戶端僅嘗試下載那個片斷。

當客戶端完成下載該片斷時,做種者看到它以前發送的片斷在其他用戶中至少有一個擁有後,才會繼續發送另外的片斷。在那之前,客戶端下載不到做種者的其他片斷,這樣不會浪費做種者的帶寬。

這種方法會有更高的效率,同時促使用戶只下載源最少的數據,降低了多餘數據的發送,限制了沒有為該群傳輸數據的用戶而發送的數據量。在這之前,做種者可能需要上傳文件總大小的 1.5 到 2 倍,其他用戶才可能成為種子。但是,使用超級種子模式的單個客戶端發布大的文件只需上傳文件大小的 1.05 倍就能成為種子。這是標準做種效率的 1.5 到 2 倍。

不推薦一般用戶採用超級種子模式。雖然它有助於稀少數據的擴散,但是它限制了客戶端下載片斷的選擇,同時限制了客戶端下載自己已得到部分的片斷。所以,超級種子模式只推薦原始做種者使用。

綜上,「原始做種者模式」或「發布者模式」是更恰當的名稱。

片斷下載策略

[編輯 | 編輯原始碼]

客戶端可以隨機順序下載片斷。

更好的方法是首先下載源最少的片斷。客戶端可以從每個其他用戶保存的原始位字段來決定,通過擁有消息來更新。然後,客戶端可以下載出現在其他用戶位字段中頻率最低的片斷。

最後階段

[編輯 | 編輯原始碼]

下載接近完成時,最後幾塊的速度有變慢的趨勢。為了加速,客戶端向其他所有擁有自己缺少塊的用戶發送請求。為防止變成無效,客戶端在每個塊完成後就向其他用戶發送一個取消的消息。

沒有已定的界限,推薦百分比或能用來作為指導的塊計數。

何時進入最後階段模式有待討論。一些客戶端以請求了所有塊來進入最後階段。其他的等到剩餘塊的數目少於傳輸中塊的數目或不超過 20 來進入該階段。保持很少的等待塊(1 或 2 塊)來將允許值減到最少,如果隨機選擇塊的請求,可能會重複下載到已有的塊。更多的協議說明見:http://hal.inria.fr/inria-00000156/en

阻塞與最佳暢通

[編輯 | 編輯原始碼]

阻塞有幾種原因。TCP 擁塞控制在同時發出許多連接時表現很差。同時,阻塞使每個用戶使用 tit-for-tat-ish 算法來確定自己得到一致的下載速度。

下面描述的阻塞算法是現在使用的。所有新算法同時在整個包括它們的網絡中工作正常,這是很重要的。

一個好的阻塞算法應有幾個標準。它應為更高的 TCP 性能改進並發上傳數。它應避免被叫做「原纖化作用」的快速阻塞和未阻塞。它應互換到讓自己下載的用戶。最後,它應偶爾測試未使用連接來發現是否比當前使用的更好,這叫做最佳暢通。

當前使用的阻塞算法通過每 10 秒鐘改變被阻塞用戶來避免原纖化作用。

互換和上傳數目的改進是由擁有最佳上傳速度和感興趣的 4 個未阻塞用戶來控制的。這將使客戶端的下載速度變得最大。這 4 個用戶被稱為下載者,因為它們對從客戶端的下載感興趣。

與下載者相比,具有較高上傳速度的用戶對未阻塞不感興趣。如果它們感興趣,具有最低上傳速度的下載者將被阻塞。如果客戶端擁有完成的文件,它使用上傳速度而不是下載速度來決定哪一個用戶未阻塞。

對於最佳暢通,在任何時候只有一個未阻塞用戶,而不管它的上傳速度(如果感興趣,它會成為 4 個允許的下載者之一)。最佳暢通的用戶 30 秒循環一次。最新連接的用戶有 3 次可能作為循環中當前的最佳暢通。這給它們得到一個完成塊就上傳的機會。

反冷落

[編輯 | 編輯原始碼]

(擴展不在官方協議中)

偶爾一個 BitTorrent 用戶會被其他用戶冷落,它先前從那些用戶中下載了數據。在這種情況下,它通常得到很低的下載速度,直到最佳暢通找到更好的用戶。為了緩和此問題,當過了 1 分鐘而沒有從某個用戶得到一個片斷,BitTorrent 認為它被那個用戶「冷落」了,不上傳給那個用戶(除了最佳暢通以外)。這會頻繁導致超過 1 個的用戶同時變成最佳暢通(一個例外是最佳暢通,規則如上所述),它會使波動的下載速度回復得更快。

相關文檔

[編輯 | 編輯原始碼]

請參閱

[編輯 | 編輯原始碼]