bt協議詳解 DHT篇(下)
最近開發了一個免費教程的網站,產生了仔細了解bt協議的想法,這篇文章是bt協議詳解系列的第三篇,后續還會寫一些關於搜索和索引的東西,都是在開發這個網站的過程中學習到的技術,敬請期待。
文章主要內容來自於對DHT Protocol的翻譯,如果大家感興趣的話,可以閱讀一下英文原版。
為了大家閱讀的方便,把文章分成了上下篇,兩篇加在一起快1w字了,確實看的比較累。
接上篇。
5 Torrent文件擴展
一個無tracker的torrent文件字典不包含announce關鍵字,而使用一個nodes關鍵字來替代。這個關鍵字對應的內容應該設置為torrent創建者的路由表中K個最接近的nodes。可供選擇的,這個關鍵字也可以設置為一個已知的可用節點,比如這個torrent文件的創建者。請不要自動加入router.bittorrent.com到torrent文件中或者自動加入這個node到客戶端路由表中。
nodes= [["
nodes= [["127.0.0.1", 6881], ["your.router.node",4804]]
6 KRPC協議
KRPC協議是由B編碼組成的一個簡單的RPC結構,他使用UDP報文發送。一個獨立的請求包被發出去然后一個獨立的包被回復。這個協議沒有重發。它包含3種消息:請求,回復和錯誤。對DHT協議而言,這里有4種請求:ping,find_node,get_peers,和announce_peer。
一個KRPC消息由一個獨立的字典組成,其中有2個關鍵字是所有的消息都包含的,其余的附加關鍵字取決於消息類型。每一個消息都包含t關鍵字,它是一個代表了transactionID的字符串類型。transactionID由請求node產生,並且回復中要包含回顯該字段,所以回復可能對應一個節點的多個請求。transactionID應當被編碼為一個短的二進制字符串,比如2個字節,這樣就可以對應2^16個請求。另一個每個KRPC消息都包含的關鍵字是y,它由一個字節組成,表明這個消息的類型。y對應的值有三種情況:q表示請求,r表示回復,e表示錯誤。
聯系信息編碼
Peers的聯系信息被編碼為6字節的字符串。又被稱為"CompactIP-address/port info",其中前4個字節是網絡字節序的IP地址,后2個字節是網絡字節序的端口。
Nodes的聯系信息被編碼為26字節的字符串。又被稱為"Compactnode info",其中前20字節是網絡字節序的nodeID,后面6個字節是peers的"CompactIP-address/port info"。
請求
請求,對應於KPRC消息字典中的“y”關鍵字的值是“q”,它包含2個附加的關鍵字“q”和“a”。關鍵字“q”是一個字符串類型,包含了請求的方法名字。關鍵字“a”一個字典類型包含了請求所附加的參數。
回復
回復,對應於KPRC消息字典中的“y”關鍵字的值是“r”,包含了一個附加的關鍵字r。關鍵字“r”是一個字典類型,包含了返回的值。發送回復消息是在正確解析了請求消息的基礎上完成的。
錯誤
錯誤,對應於KPRC消息字典中的y關鍵字的值是“e”,包含一個附加的關鍵字e。關鍵字“e”是一個列表類型。第一個元素是一個數字類型,表明了錯誤碼。第二個元素是一個字符串類型,表明了錯誤信息。當一個請求不能解析或出錯時,錯誤包將被發送。下表描述了可能出現的錯誤碼:
錯誤碼
錯誤描述
201
一般錯誤
202
服務錯誤
203
協議錯誤,比如不規范的包,無效的參數,或者錯誤的token
204
未知方法
錯誤包例子:
一般錯誤={"t":"aa", "y":"e", "e":[201,"A Generic Error Ocurred"]}
B編碼=d1:eli201e23:AGenericErrorOcurrede1:t2:aa1:y1:ee
7 DHT請求
所有的請求都包含一個關鍵字id,它包含了請求節點的nodeID。所有的回復也包含關鍵字id,它包含了回復節點的nodeID。
ping
最基礎的請求就是ping。這時KPRC協議中的“q”=“ping”。Ping請求包含一個參數id,它是一個20字節的字符串包含了發送者網絡字節序的nodeID。對應的ping回復也包含一個參數id,包含了回復者的nodeID。
參數: {"id" : "
回復:{"id" : "
報文包例子
ping請求={"t":"aa", "y":"q","q":"ping", "a":{"id":"abcdefghij0123456789"}}
B編碼=d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe
回復={"t":"aa", "y":"r", "r":{"id":"mnopqrstuvwxyz123456"}}
B編碼=d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
find_node
Findnode被用來查找給定ID的node的聯系信息。這時KPRC協議中的q=“find_node”。find_node請求包含2個參數,第一個參數是id,包含了請求node的nodeID。第二個參數是target,包含了請求者正在查找的node的nodeID。當一個node接收到了find_node的請求,他應該給出對應的回復,回復中包含2個關鍵字id和nodes,nodes是一個字符串類型,包含了被請求節點的路由表中最接近目標node的K(8)個最接近的nodes的聯系信息。
參數: {"id" : "
回復:{"id" : "
報文包例子
find_node請求={"t":"aa", "y":"q","q":"find_node", "a":{"id":"abcdefghij0123456789","target":"mnopqrstuvwxyz123456"}}
B編碼=d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e1:q9:find_node1:t2:aa1:y1:qe
回復={"t":"aa", "y":"r", "r":{"id":"0123456789abcdefghij", "nodes":"def456..."}}
B編碼=d1:rd2:id20:0123456789abcdefghij5:nodes9:def456...e1:t2:aa1:y1:re
get_peers
Getpeers與torrent文件的info_hash有關。這時KPRC協議中的”q”=”get_peers”。get_peers請求包含2個參數。第一個參數是id,包含了請求node的nodeID。第二個參數是info_hash,它代表torrent文件的infohash。如果被請求的節點有對應info_hash的peers,他將返回一個關鍵字values,這是一個列表類型的字符串。每一個字符串包含了"CompactIP-address/portinfo"格式的peers信息。如果被請求的節點沒有這個infohash的peers,那么他將返回關鍵字nodes,這個關鍵字包含了被請求節點的路由表中離info_hash最近的K個nodes,使用"Compactnodeinfo"格式回復。在這兩種情況下,關鍵字token都將被返回。token關鍵字在今后的annouce_peer請求中必須要攜帶。Token是一個短的二進制字符串。
參數: {"id" : "
回復:{"id" : "
or:{"id" : "
報文包例子
get_peers請求={"t":"aa", "y":"q","q":"get_peers", "a":{"id":"abcdefghij0123456789","info_hash":"mnopqrstuvwxyz123456"}}
B編碼=d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e1:q9:get_peers1:t2:aa1:y1:qe
回復peers ={"t":"aa", "y":"r", "r":{"id":"abcdefghij0123456789", "token":"aoeusnth","values": ["axje.u", "idhtnm"]}}
B編碼=d1:rd2:id20:abcdefghij01234567895:token8:aoeusnth6:valuesl6:axje.u6:idhtnmee1:t2:aa1:y1:re
回復最接近的nodes= {"t":"aa", "y":"r", "r":{"id":"abcdefghij0123456789", "token":"aoeusnth","nodes": "def456..."}}
B編碼=d1:rd2:id20:abcdefghij01234567895:nodes9:def456...5:token8:aoeusnthe1:t2:aa1:y1:re
announce_peer
這個請求用來表明發出announce_peer請求的node,正在某個端口下載torrent文件。announce_peer包含4個參數。第一個參數是id,包含了請求node的nodeID;第二個參數是info_hash,包含了torrent文件的infohash;第三個參數是port包含了整型的端口號,表明peer在哪個端口下載;第四個參數數是token,這是在之前的get_peers請求中收到的回復中包含的。收到announce_peer請求的node必須檢查這個token與之前我們回復給這個節點get_peers的token是否相同。如果相同,那么被請求的節點將記錄發送announce_peer節點的IP和請求中包含的port端口號在peer聯系信息中對應的infohash下。
參數: {"id": "
回復: {"id": "
報文包例子
announce_peers請求={"t":"aa", "y":"q","q":"announce_peer", "a":{"id":"abcdefghij0123456789","info_hash":"mnopqrstuvwxyz123456", "port":6881, "token": "aoeusnth"}}
B編碼=d1:ad2:id20:abcdefghij01234567899:info_hash20:
mnopqrstuvwxyz1234564:porti6881e5:token8:aoeusnthe1:q13:announce_peer1:t2:aa1:y1:qe
回復={"t":"aa", "y":"r", "r":{"id":"mnopqrstuvwxyz123456"}}
B編碼=d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
跳轉到上篇。
本文來自 免費教程網