BT協(xié)議
bt種子文件
編碼 bencode
bencode 有 4 種數(shù)據(jù)類型: string, integer, list 和 dictionary丝蹭。
-
string
e.g.: <字符串長度>:<字符串>
-
integer
e.g.: i<整數(shù)>e
-
list
e.g.: l數(shù)據(jù)1數(shù)據(jù)2數(shù)據(jù)3e
-
dictionary
e.g.:
d[key1][value1][key2][value2][…]e
移迫,其中 key 必須是 string 而且按照字母順序排序
種子文件結(jié)構(gòu)
-
info
字典叫胁,描述種子內(nèi)包含的文件列表信息行您,這里有兩種類型薄霜,一是單文件的送膳,二是多文件的瘦癌,具體看后面的說明。 -
announce
字節(jié)串乌叶,描述 Tracker 的 URL盆偿。 -
announce-list
列表,可選准浴,這是一個對官方規(guī)范的擴(kuò)展項(xiàng)事扭,提供后向兼容。 -
creation date
字節(jié)串乐横,可選求橄,這是一個UNIX時間戳,表示種子文件的創(chuàng)建時間葡公。 -
comment
字節(jié)串罐农,可選,自由描述字段催什,一般描述種子的制作者涵亏。 -
created by
字節(jié)串,可選蒲凶,描述用于制作這個種子文件的程序气筋。 -
encoding
字節(jié)串,可選旋圆,描述 info.pieces 字段的編碼方式宠默。
無論是單文件格式還是多文件格式的種子文件,其 info 字段下都可以包含以下 3 個字段:
-
piece length
整數(shù)臂聋,表示一個分片的長度(單位:字節(jié))光稼,稱之為 分片單位。 -
pieces
字節(jié)串孩等,是由多個分片的 SHA-1校驗(yàn)碼(20字節(jié)/個) 拼湊而成的字節(jié)串艾君,因此其長度總是為20的倍數(shù)。 -
private
整數(shù)肄方,可選冰垄,如果這個值被置為1,那么 BT客戶端 必須通過向 種子文件 中指定的 Tracker 匯報(bào)自身的存在权她,從而獲取其它 伙伴 的信息虹茶。反之如果置0,客戶端 可以通過其它方法獲取其它伙伴隅要,例如 PEX蝴罪,DHT。因此步清,private 字段也可以理解為“禁止通過其它途徑獲取伙伴信息”要门。
當(dāng)種子內(nèi)僅包含一個文件的信息時虏肾,其 info 字段 內(nèi)必須包括如下字段:
-
name
字節(jié)串,種子內(nèi)包含的唯一文件的名稱欢搜,這不是強(qiáng)制性的命名封豪,僅作參考。(下載時可以修改保存的文件名) -
length
整數(shù)炒瘟,種子內(nèi)包含的唯一文件的大小吹埠,單位是字節(jié)。 -
md5sum
字節(jié)串疮装,可選缘琅,這是一個32位的16進(jìn)制字符串,表示種子內(nèi)包含的唯一文件的 MD5 校驗(yàn)值廓推。盡管幾乎所有BT客戶端都未使用到這個字段胯杭,但是它仍被保留作為兼容性字段。
當(dāng)種子內(nèi)包含多個文件的信息時受啥,其 info 字段 內(nèi)必須包括如下字段:
name
字節(jié)串,種子內(nèi)所有文件的總名稱鸽心,BT客戶端下載時默認(rèn)使用它作為資源的目錄名稱滚局,同理,這不是強(qiáng)制性的命名顽频,僅作參考藤肢。(下載時可以修改保存的目錄名)files列表,這是一個由多個字典組成的列表糯景,每個字典對應(yīng)一個文件的信息嘁圈,這些字典的格式如下:
-
length
整數(shù),文件的大小蟀淮,單位是字節(jié)最住。 -
md5sum
字節(jié)串,可選怠惶,這是一個32位的16進(jìn)制字符串涨缚,表示該文件的 MD5 校驗(yàn)值。盡管幾乎所有BT客戶端都未使用到這個字段策治,但是它仍被保留作為兼容性字段脓魏。 -
path
列表 這是一個特殊的文件路徑表示方式。假設(shè)一個文件在種子內(nèi)對應(yīng)的相對路徑是a/bb/ccc/hello.txt
通惫,那么將其根據(jù)/
分割開茂翔,得到順序列表[ 'a', 'bb', 'ccc', 'hello.txt' ]
,經(jīng)過 BEncoding 編碼后就是l1:a2:bb3:ccc9:hello.txte
履腋。
Tracker服務(wù)器
一般有http和udp兩種
入?yún)?/h3>
-
info_hash
:元信息文件中 20 字節(jié)的 SHA-1 散列值珊燎。注意此值會進(jìn)入編碼字典中,如上述的信息關(guān)鍵字的定義所述。與不需編碼的 peer_id 相比俐末,它總是被 URL 編碼料按。
-
peer_id
:客戶端 ID ,客戶端用來唯一標(biāo)識自己 ID 的 20 字節(jié)的串卓箫,它在客戶端啟動時生成载矿。允許為任何值,包括二進(jìn)制數(shù)據(jù)烹卒。目前沒有特定的算法來生成客戶端 ID闷盔。但是,人們會認(rèn)為它至少對于自己的本地機(jī)器是唯一的旅急,從而應(yīng)該像進(jìn)程 ID 一樣合并數(shù)據(jù)逢勾,也可能在啟動時由時標(biāo)記錄。見本區(qū)域下面的一般客戶端編碼的 peer_id藐吮。
-
port
:客戶端監(jiān)聽的端口號溺拱。BitTorrent 所使用的典型端口是 6881-6889。如果此范圍的端口都無效谣辞,可以選擇其他的迫摔。
-
uploaded
:從客戶端發(fā)送“已開始”事件到服務(wù)器算起的上傳總量,數(shù)值采用 10 進(jìn)制的 ASCII泥从。對于沒有在官方規(guī)范明確指出的句占,該值應(yīng)為已上傳的字節(jié)總數(shù)。
-
downloaded
:從客戶端發(fā)送“已開始”事件到服務(wù)器算起的下載總量躯嫉,數(shù)值采用 10 進(jìn)制的 ASCII纱烘。對于沒有在官方規(guī)范明確指出的,該值應(yīng)為已下載的字節(jié)總數(shù)祈餐。
-
left
:客戶端需要下載的字節(jié)數(shù)擂啥,以 10 進(jìn)制 ASCII 編碼。
-
no_peer_id
:客戶端接受一個緊密的響應(yīng)昼弟∑∷客戶端列表由客戶端串代替,此串中每個客戶端都編碼成 6 字節(jié)舱痘。前 4 字節(jié)是主機(jī)名(以網(wǎng)絡(luò)的字節(jié)順序)变骡,后兩個字節(jié)是端口號(同樣以網(wǎng)絡(luò)字節(jié)的順序)。
-
event
:如果被指定芭逝,則是已開始塌碌,已完成,已停止中的一個旬盯,或者為空(表示未指定)台妆。如果未指定翎猛,此請求為常規(guī)時間間隔中的一次運(yùn)行。
-
started
:向服務(wù)器發(fā)送的第一個請求接剩,必須包含開始值的事件關(guān)鍵字切厘。
-
stopped
:如果客戶端關(guān)機(jī)則須發(fā)送到服務(wù)器上。
-
completed
:完成下載時必須發(fā)送到服務(wù)器上懊缺。但是疫稿,當(dāng)客戶端啟動時下載完成度為 100%(即:做種中)則不會發(fā)送【榱剑可能這是允許服務(wù)器增加“已完成下載”的方法遗座。
-
ip
:可選】“猓客戶端的真實(shí) IP 地址途蒋,以點(diǎn)分四元組格式或 RFC3513 中定義的 16 進(jìn)制 IPv6 地址。注意:大體上此參數(shù)沒有客戶端地址重要馋记,它能由 IP 地址決定号坡,HTTP 請求也來自該處。僅在請求參與的 IP 地址不是客戶端的 IP 地址的情況下才需要梯醒。這種情況發(fā)生在客戶端通過代理服務(wù)器與服務(wù)器進(jìn)行通信的情形筋帖。當(dāng)客戶端和服務(wù)器同時處在本地 NAT 網(wǎng)關(guān)時也需要。原因是服務(wù)器會發(fā)出客戶端的內(nèi)部地址(RFC1918)冤馏,這是不可到達(dá)的。所以客戶端必須清楚地把自己的外部可到達(dá)的 IP 地址發(fā)送到其他客戶端中寄啼。不同的服務(wù)器對此參數(shù)的解釋有所不同逮光。某些只有當(dāng)請求參與的 IP 地址屬于 RFC1918 時才允許。有些無條件允許墩划,但有些則完全忽略涕刚。如果使用 IPv6 地址(如:2001:db8:1:2::100),則表示客戶端能通過 IPv6 進(jìn)行通信乙帮。
-
numwant
:可選杜漠。客戶端想從服務(wù)器接收的用戶數(shù)目察净。允許此值為“0”驾茴。如果不用此項(xiàng),則默認(rèn)值為 50 個用戶氢卡。
-
key
:可選锈至。一個不與任何用戶共享的另外的標(biāo)識。當(dāng) IP 地址改變后译秦,允許客戶端證明它們的標(biāo)識峡捡。
-
trackerid
:可選击碗。如果先前發(fā)布包含服務(wù)器的 id,它應(yīng)放在這里们拙。
響應(yīng)
-
failure reason
:如果當(dāng)前使用此值稍途,則其余關(guān)鍵字不會使用。該值是可讀的錯誤消息砚婆,包括請求失敗的原因械拍。(字符串)
-
warning message
:(新)與失敗原因相似,但響應(yīng)仍然會被正常處理射沟。警告消息看起來像錯誤殊者。
-
interval
:以秒計(jì)算,是客戶端發(fā)送規(guī)則請求到服務(wù)器之后等待的時間验夯。(強(qiáng)制)
-
min interval
:最小發(fā)布時間間隔猖吴。當(dāng)前客戶重發(fā)間隔不能小于此值。
-
tracker id
:一個客戶端應(yīng)在下一個通告發(fā)回的字符串挥转。如果沒有該值海蔽,先前通告會發(fā)出一個服務(wù)器 id ,不要丟棄舊的值绑谣,一直使用它党窜。
-
complete
:擁有完整文件的用戶數(shù),即做種者(整數(shù))
-
incomplete
:非種子用戶的數(shù)目借宵,也叫“吸血者”(整數(shù))
-
peers
:是字典的列表幌衣,每個值都有如下的關(guān)鍵字:
-
peer id
:用戶的自選擇 ID,如上述用來發(fā)送服務(wù)器請求的(字符串)
-
ip
:用戶的 IP 地址(IPv4 或 IPv6 格式)或域名(字符串)
-
port
:用戶的端口號(整數(shù))
DHT
概述 Overview
info_hash
:元信息文件中 20 字節(jié)的 SHA-1 散列值珊燎。注意此值會進(jìn)入編碼字典中,如上述的信息關(guān)鍵字的定義所述。與不需編碼的 peer_id 相比俐末,它總是被 URL 編碼料按。peer_id
:客戶端 ID ,客戶端用來唯一標(biāo)識自己 ID 的 20 字節(jié)的串卓箫,它在客戶端啟動時生成载矿。允許為任何值,包括二進(jìn)制數(shù)據(jù)烹卒。目前沒有特定的算法來生成客戶端 ID闷盔。但是,人們會認(rèn)為它至少對于自己的本地機(jī)器是唯一的旅急,從而應(yīng)該像進(jìn)程 ID 一樣合并數(shù)據(jù)逢勾,也可能在啟動時由時標(biāo)記錄。見本區(qū)域下面的一般客戶端編碼的 peer_id藐吮。port
:客戶端監(jiān)聽的端口號溺拱。BitTorrent 所使用的典型端口是 6881-6889。如果此范圍的端口都無效谣辞,可以選擇其他的迫摔。uploaded
:從客戶端發(fā)送“已開始”事件到服務(wù)器算起的上傳總量,數(shù)值采用 10 進(jìn)制的 ASCII泥从。對于沒有在官方規(guī)范明確指出的句占,該值應(yīng)為已上傳的字節(jié)總數(shù)。downloaded
:從客戶端發(fā)送“已開始”事件到服務(wù)器算起的下載總量躯嫉,數(shù)值采用 10 進(jìn)制的 ASCII纱烘。對于沒有在官方規(guī)范明確指出的,該值應(yīng)為已下載的字節(jié)總數(shù)祈餐。left
:客戶端需要下載的字節(jié)數(shù)擂啥,以 10 進(jìn)制 ASCII 編碼。no_peer_id
:客戶端接受一個緊密的響應(yīng)昼弟∑∷客戶端列表由客戶端串代替,此串中每個客戶端都編碼成 6 字節(jié)舱痘。前 4 字節(jié)是主機(jī)名(以網(wǎng)絡(luò)的字節(jié)順序)变骡,后兩個字節(jié)是端口號(同樣以網(wǎng)絡(luò)字節(jié)的順序)。event
:如果被指定芭逝,則是已開始塌碌,已完成,已停止中的一個旬盯,或者為空(表示未指定)台妆。如果未指定翎猛,此請求為常規(guī)時間間隔中的一次運(yùn)行。-
started
:向服務(wù)器發(fā)送的第一個請求接剩,必須包含開始值的事件關(guān)鍵字切厘。
-
stopped
:如果客戶端關(guān)機(jī)則須發(fā)送到服務(wù)器上。
-
completed
:完成下載時必須發(fā)送到服務(wù)器上懊缺。但是疫稿,當(dāng)客戶端啟動時下載完成度為 100%(即:做種中)則不會發(fā)送【榱剑可能這是允許服務(wù)器增加“已完成下載”的方法遗座。
ip
:可選】“猓客戶端的真實(shí) IP 地址途蒋,以點(diǎn)分四元組格式或 RFC3513 中定義的 16 進(jìn)制 IPv6 地址。注意:大體上此參數(shù)沒有客戶端地址重要馋记,它能由 IP 地址決定号坡,HTTP 請求也來自該處。僅在請求參與的 IP 地址不是客戶端的 IP 地址的情況下才需要梯醒。這種情況發(fā)生在客戶端通過代理服務(wù)器與服務(wù)器進(jìn)行通信的情形筋帖。當(dāng)客戶端和服務(wù)器同時處在本地 NAT 網(wǎng)關(guān)時也需要。原因是服務(wù)器會發(fā)出客戶端的內(nèi)部地址(RFC1918)冤馏,這是不可到達(dá)的。所以客戶端必須清楚地把自己的外部可到達(dá)的 IP 地址發(fā)送到其他客戶端中寄啼。不同的服務(wù)器對此參數(shù)的解釋有所不同逮光。某些只有當(dāng)請求參與的 IP 地址屬于 RFC1918 時才允許。有些無條件允許墩划,但有些則完全忽略涕刚。如果使用 IPv6 地址(如:2001:db8:1:2::100),則表示客戶端能通過 IPv6 進(jìn)行通信乙帮。numwant
:可選杜漠。客戶端想從服務(wù)器接收的用戶數(shù)目察净。允許此值為“0”驾茴。如果不用此項(xiàng),則默認(rèn)值為 50 個用戶氢卡。key
:可選锈至。一個不與任何用戶共享的另外的標(biāo)識。當(dāng) IP 地址改變后译秦,允許客戶端證明它們的標(biāo)識峡捡。trackerid
:可選击碗。如果先前發(fā)布包含服務(wù)器的 id,它應(yīng)放在這里们拙。failure reason
:如果當(dāng)前使用此值稍途,則其余關(guān)鍵字不會使用。該值是可讀的錯誤消息砚婆,包括請求失敗的原因械拍。(字符串)warning message
:(新)與失敗原因相似,但響應(yīng)仍然會被正常處理射沟。警告消息看起來像錯誤殊者。interval
:以秒計(jì)算,是客戶端發(fā)送規(guī)則請求到服務(wù)器之后等待的時間验夯。(強(qiáng)制)min interval
:最小發(fā)布時間間隔猖吴。當(dāng)前客戶重發(fā)間隔不能小于此值。tracker id
:一個客戶端應(yīng)在下一個通告發(fā)回的字符串挥转。如果沒有該值海蔽,先前通告會發(fā)出一個服務(wù)器 id ,不要丟棄舊的值绑谣,一直使用它党窜。complete
:擁有完整文件的用戶數(shù),即做種者(整數(shù))incomplete
:非種子用戶的數(shù)目借宵,也叫“吸血者”(整數(shù))peers
:是字典的列表幌衣,每個值都有如下的關(guān)鍵字:-
peer id
:用戶的自選擇 ID,如上述用來發(fā)送服務(wù)器請求的(字符串)
-
ip
:用戶的 IP 地址(IPv4 或 IPv6 格式)或域名(字符串)
-
port
:用戶的端口號(整數(shù))
每個節(jié)點(diǎn)有一個全局唯一的標(biāo)識符壤玫,作為 "node ID"豁护。節(jié)點(diǎn) ID 是一個隨機(jī)選擇的 160bit 空間,BitTorrent infohash[2] 也使用這樣的 160bit 空間欲间。 "距離"用來比較兩個節(jié)點(diǎn) ID 之間或者節(jié)點(diǎn) ID 和 infohash 之間的"遠(yuǎn)近"楚里。節(jié)點(diǎn)必須維護(hù)一個路由表,路由表中含有一部分其它節(jié)點(diǎn)的聯(lián)系信息猎贴。其它節(jié)點(diǎn)距離自己越近時班缎,路由表信息越詳細(xì)。因此每個節(jié)點(diǎn)都知道 DHT 中離自己很"近"的節(jié)點(diǎn)的聯(lián)系信息她渴,而離自己非常遠(yuǎn)的 ID 的聯(lián)系信息卻知道的很少达址。
在 Kademlia 網(wǎng)絡(luò)中,距離是通過異或(XOR)計(jì)算的趁耗,結(jié)果為無符號整數(shù)苏携。distance(A, B) = |A xor B|
,值越小表示越近对粪。
當(dāng)節(jié)點(diǎn)要為 torrent 尋找 peer 時右冻,它將自己路由表中的節(jié)點(diǎn) ID 和 torrent 的 infohash 進(jìn)行"距離對比"装蓬。然后向路由表中離 infohash 最近的節(jié)點(diǎn)發(fā)送請求,問它們正在下載這個 torrent 的 peer 的聯(lián)系信息纱扭。如果一個被聯(lián)系的節(jié)點(diǎn)知道下載這個 torrent 的 peer 信息牍帚,那個 peer 的聯(lián)系信息將被回復(fù)給當(dāng)前節(jié)點(diǎn)。否則乳蛾,那個被聯(lián)系的節(jié)點(diǎn)則必須回復(fù)在它的路由表中離該 torrent 的 infohash 最近的節(jié)點(diǎn)的聯(lián)系信息暗赶。最初的節(jié)點(diǎn)重復(fù)地請求比目標(biāo) infohash 更近的節(jié)點(diǎn),直到不能再找到更近的節(jié)點(diǎn)為止肃叶。查詢完了之后蹂随,客戶端把自己作為一個 peer 插入到所有回復(fù)節(jié)點(diǎn)中離種子最近的那個節(jié)點(diǎn)中。
請求 peer 的返回值包含一個不透明的值因惭,稱之為"令牌(token)"岳锁。如果一個節(jié)點(diǎn)宣布它所控制的 peer 正在下載一個種子,它必須在回復(fù)請求節(jié)點(diǎn)的同時蹦魔,附加上對方向我們發(fā)送的最近的"令牌(token)"激率。這樣當(dāng)一個節(jié)點(diǎn)試圖"宣布"正在下載一個種子時,被請求的節(jié)點(diǎn)核對令牌和發(fā)出請求的節(jié)點(diǎn)的 IP 地址勿决。這是為了防止惡意的主機(jī)登記其它主機(jī)的種子乒躺。由于令牌僅僅由請求節(jié)點(diǎn)返回給收到令牌的同一個節(jié)點(diǎn),所以沒有規(guī)定他的具體實(shí)現(xiàn)低缩。但是令牌必須在一個規(guī)定的時間內(nèi)被接受嘉冒,超時后令牌則失效。在 BitTorrent 的實(shí)現(xiàn)中咆繁,token 是在 IP 地址后面連接一個 secret(通常是一個隨機(jī)數(shù))健爬,這個 secret 每五分鐘改變一次,其中 token 在十分鐘以內(nèi)是可接受的么介。
路由表 Routing Table
每個節(jié)點(diǎn)維護(hù)一個路由表保存已知的好節(jié)點(diǎn)。路由表中的節(jié)點(diǎn)是用來作為在 DHT 中請求的起始點(diǎn)蜕衡。路由表中的節(jié)點(diǎn)是在不斷的向其他節(jié)點(diǎn)請求過程中壤短,對方節(jié)點(diǎn)回復(fù)的。
并不是我們在請求過程中收到得節(jié)點(diǎn)都是平等的慨仿,有的節(jié)點(diǎn)是好的久脯,而另一些則不是。許多使用 DHT 協(xié)議的節(jié)點(diǎn)都可以發(fā)送請求并接收回復(fù)镰吆,但是不能主動回復(fù)其他節(jié)點(diǎn)的請求帘撰。節(jié)點(diǎn)的路由表只包含已知的好節(jié)點(diǎn),這很重要万皿。好節(jié)點(diǎn)是指在過去的 15 分鐘以內(nèi)摧找,曾經(jīng)對我們的某一個請求給出過回復(fù)的節(jié)點(diǎn)核行,或者曾經(jīng)對我們的請求給出過一個回復(fù)(不用在15分鐘以內(nèi)),并且在過去的 15 分鐘給我們發(fā)送過請求蹬耘。上述兩種情況都可將節(jié)點(diǎn)視為好節(jié)點(diǎn)芝雪。在 15 分鐘之后,對方?jīng)]有上述 2 種情況發(fā)生综苔,這個節(jié)點(diǎn)將變?yōu)榭梢傻某拖怠.?dāng)節(jié)點(diǎn)不能給我們的一系列請求給出回復(fù)時,這個節(jié)點(diǎn)將變?yōu)閴牡娜缟浮O啾饶切┪粗獱顟B(tài)的節(jié)點(diǎn)堡牡,已知的好節(jié)點(diǎn)會被給于更高的優(yōu)先級。
路由表覆蓋從 0 到 2^160 全部的節(jié)點(diǎn) ID 空間杨刨。路由表又被劃分為桶(bucket)晤柄,每個桶包含一部分的 ID 空間∈眉蓿空的路由表只有一個桶可免,它的 ID 范圍從 min=0 到 max=2^160。當(dāng) ID 為 N
的節(jié)點(diǎn)插入到表中時做粤,它將被放到 ID 范圍在 min <= N < max
的 桶 中浇借。空的路由表只有一個桶怕品,所以所有的節(jié)點(diǎn)都將被放到這個桶中妇垢。每個桶最多只能保存 K 個節(jié)點(diǎn),當(dāng)前 K=8肉康。當(dāng)一個桶放滿了好節(jié)點(diǎn)之后闯估,將不再允許新的節(jié)點(diǎn)加入,除非我們自身的節(jié)點(diǎn) ID 在這個桶的范圍內(nèi)吼和。在這樣的情況下涨薪,這個桶將被分裂為 2 個新的桶,每個新桶的范圍都是原來舊桶的一半炫乓。原來舊桶中的節(jié)點(diǎn)將被重新分配到這兩個新的桶中刚夺。如果一個新表只有一個桶,這個包含整個范圍的桶將總被分裂為 2 個新的桶末捣,每個桶的覆蓋范圍從 0..2^159 和 2159..2160侠姑。
當(dāng)桶裝滿了好節(jié)點(diǎn),新的節(jié)點(diǎn)會被丟棄箩做。一旦桶中的某個節(jié)點(diǎn)變?yōu)榱藟牡墓?jié)點(diǎn)莽红,那么我們就用新的節(jié)點(diǎn)來替換這個壞的節(jié)點(diǎn)。如果桶中有在 15 分鐘內(nèi)都沒有活躍過的節(jié)點(diǎn)邦邦,我們將這樣的節(jié)點(diǎn)視為可疑的節(jié)點(diǎn)安吁,這時我們向最久沒有聯(lián)系的節(jié)點(diǎn)發(fā)送 ping醉蚁。如果被 ping 的節(jié)點(diǎn)給出了回復(fù),那么我們向下一個可疑的節(jié)點(diǎn)發(fā)送 ping柳畔,不斷這樣循環(huán)下去馍管,直到有某一個節(jié)點(diǎn)沒有給出 ping 的回復(fù),或者當(dāng)前桶中的所有節(jié)點(diǎn)都是好的(也就是所有節(jié)點(diǎn)都不是可疑節(jié)點(diǎn)薪韩,他們在過去 15 分鐘內(nèi)都有活動)确沸。如果桶中的某個節(jié)點(diǎn)沒有對我們的 ping 給出回復(fù),我們最好再試一次(再發(fā)送一次 ping俘陷,因?yàn)檫@個節(jié)點(diǎn)也許仍然是活躍的罗捎,但由于網(wǎng)絡(luò)擁塞,所以發(fā)生了丟包現(xiàn)象拉盾,注意 DHT 的包都是 UDP 的)桨菜,而不是立即丟棄這個節(jié)點(diǎn)或者直接用新節(jié)點(diǎn)來替代它。這樣捉偏,我們得路由表將充滿穩(wěn)定的長時間在線的節(jié)點(diǎn)倒得。
每個桶都應(yīng)該維持一個 lastchange
字段來表明桶中節(jié)點(diǎn)的"新鮮"度。當(dāng)桶中的節(jié)點(diǎn)被 ping 并給出了回復(fù)夭禽,或者一個節(jié)點(diǎn)被加入到了桶霞掺,或者一個節(jié)點(diǎn)被新的節(jié)點(diǎn)所替代,桶的 lastchange
字段都應(yīng)當(dāng)被更新讹躯。如果一個桶的 lastchange
在過去的 15 分鐘內(nèi)都沒有變化菩彬,那么我們將更新它。這個更新桶操作是這樣完成的:從這個桶所覆蓋的范圍中隨機(jī)選擇一個 ID潮梯,并對這個 ID 執(zhí)行 find_nodes
查找操作骗灶。常常收到請求的節(jié)點(diǎn)通常不需要常常更新自己的桶,反之秉馏,不常常收到請求的節(jié)點(diǎn)常常需要周期性的執(zhí)行更新所有桶的操作耙旦,這樣才能保證當(dāng)我們用到 DHT 的時候,里面有足夠多的好的節(jié)點(diǎn)萝究。
在插入第一個節(jié)點(diǎn)到路由表并啟動服務(wù)后免都,這個節(jié)點(diǎn)應(yīng)試著查找 DHT 中離自己更近的節(jié)點(diǎn),這個查找工作是通過不斷的發(fā)出find_node
消息給越來越近的節(jié)點(diǎn)來完成的糊肤,當(dāng)不能找到更近的節(jié)點(diǎn)時,這個擴(kuò)散工作就結(jié)束了氓鄙。路由表應(yīng)當(dāng)被啟動工作和客戶端軟件保存(也就是啟動的時候從客戶端中讀取路由表信息馆揉,結(jié)束的時候客戶端軟件記錄到文件中)。
協(xié)議消息
Kademlia協(xié)議共有四種消息
1. PING消息: 用來測試節(jié)點(diǎn)是否仍然在線
2. STORE消息: 在某個節(jié)點(diǎn)中存儲一個鍵值對
3. FIND_NODE消息: 消息請求的接收者將返回自己桶中離請求鍵值最近的K個節(jié)點(diǎn): 將請求者請求的節(jié)點(diǎn)HASH和自己的HASH進(jìn)行XOR計(jì)算抖拦,將計(jì)算結(jié)果
4. FIND_VALUE消息: 與FIND_NODE一樣升酣,不過當(dāng)請求的接收者存有請求者所請求的鍵的時候舷暮,它將返回相應(yīng)鍵的值
DHT嗅探器的原理
DHT這種對等分布式網(wǎng)絡(luò)在帶來抗DDOS的優(yōu)點(diǎn)的同時,也帶來了一些缺點(diǎn)
1. 偽造攻擊: 有些不聽話的用戶可能會在DHT網(wǎng)絡(luò)里搗亂噩茄,譬如說撒謊下面,明明自己不是奧巴馬,卻偏說自己是奧巴馬绩聘,這樣會誤導(dǎo)其他人無法正常獲取想要的資源
2. 嗅探攻擊: 另外沥割,用戶在DHT網(wǎng)絡(luò)里的隱私可能會被竊聽,因?yàn)樵贒HT網(wǎng)絡(luò)里跟其他用戶交換資源的時候凿菩,難免會暴露自己的IP地址机杜,所以別人就會知道你有什么資源,你在請求什么資源了衅谷。這也是目前DHT網(wǎng)絡(luò)里一直存在的一個弱點(diǎn)
參考:
https://wiki.theory.org/index.php/BitTorrentSpecification#Notes
https://fenying.gitbooks.io/bittorrent-specification-chinese-edition/content/