dht网络协议 服务器,概述DHT网络
一、文件共享網(wǎng)絡(luò)
第一代
中央服務(wù)器。以文件服務(wù)器作為中心,典型的提供FTP的服務(wù)器。這種方式對服務(wù)器帶寬壓力和機器性能壓力巨大。而且,這種單點集權(quán)的模式風險非常大,一旦出現(xiàn)故障,整個服務(wù)將停止。
第二代
泛洪式查詢。網(wǎng)絡(luò)中每一個節(jié)點都向他鄰居節(jié)點詢問是否擁有資源,如果沒有,鄰居繼續(xù)向他的鄰居詢問。這種廣播式的查詢?nèi)秉c明顯,每次向外傳播都是指數(shù)級,很容易就形成蝴蝶效應(yīng)般的影響,對網(wǎng)絡(luò)資源消耗非常大,而且容易形成網(wǎng)絡(luò)風暴。以至于要對廣播的廣度和深度進行限制。
典型的例子是Gnutella,2000年的一種文件共享網(wǎng)絡(luò)。廣播廣度被限制在5個鄰居,深度不大于7跳。但5^7=78125這個數(shù)量也是很驚人。盡管它沒有直接查詢中心節(jié)點有效率,但它不再依賴一個中心化的索引節(jié)點。
第三代
BTtorrent-tracker。BT的網(wǎng)絡(luò)架構(gòu)中存在一個中心服務(wù)器Tracker,用來保存BT網(wǎng)絡(luò)巾各節(jié)點的IP地址和端口等信息。下載節(jié)點剛加入網(wǎng)絡(luò)時從Trakcer上獲得其他節(jié)點的地址信息,同時在tracker中注冊自己的信息成為一個peer。實現(xiàn)一個節(jié)點同時與多個節(jié)點交互。
第四代
Bttorrent-DHT。雖然第三代文件共享網(wǎng)絡(luò)實現(xiàn)了P2P,但也有個缺點,如果tracker被屏蔽或者被黑,那么新節(jié)點無法注冊,也無法獲得peer列表,整個P2P網(wǎng)絡(luò)就癱瘓。DHT(分布式哈希表)網(wǎng)絡(luò)的出現(xiàn),作為BT協(xié)議強而有力的拓展,解決了以上問題。
DHT全稱?Distributed Hash Table,中文翻譯分布式哈希表。它是一種去中心化的分布式系統(tǒng),特點主要有自動去中心化,強大的容錯能力,支持擴展。另外它規(guī)定了自己的架構(gòu),包括keyspace和overlay network(覆蓋網(wǎng)絡(luò))兩部分。但是他沒有規(guī)定具體的算法細節(jié),所以出現(xiàn)了很多不同的實現(xiàn)方式,比如Chord,Pastry,Kademlia等。BitTorrent中的DHT是基于Kademlia的一種變形。本文也是根據(jù)Kademlia協(xié)議描述DHT網(wǎng)絡(luò)。
二、相關(guān)名詞
peer:一個實現(xiàn)了BT協(xié)議并且開啟了tcp監(jiān)聽端口的bt客戶端或者服務(wù)器
node:一個實現(xiàn)了DHT協(xié)議并且開啟了udp監(jiān)聽端口的bt客戶端或者服務(wù)器
tracker:最終指引請求者找到目標peer的主機。在DHT網(wǎng)絡(luò)中,存儲了peer信息的node充當一個虛擬tracker的角色。
info_hash:一個由40位16進制數(shù)字組成的字符串,總共有160bit。由SHA-1計算torrent文件中的info得出的作為資源的唯一標識。
B編碼(Bencode編碼):一種torrent文件信息存儲格式
哈希表:也稱散列表。根據(jù)關(guān)鍵碼值(Key value)而直接進行訪問的數(shù)據(jù)結(jié)構(gòu)。這個映射函數(shù)叫哈希函數(shù),存放記錄的數(shù)組叫哈希表。
三、Kademlia協(xié)議(簡稱 Kad)
1.兩個關(guān)鍵的id:
nodeid,節(jié)點id。節(jié)點包含了網(wǎng)絡(luò)ip地址和端口號,由唯一的節(jié)點id指向這一個節(jié)點。節(jié)點id為160位的二進制表示。
key。網(wǎng)絡(luò)中的資源名索引和資源名以key-value鍵值對的形式表示,資源名經(jīng)過哈希函數(shù)計算,轉(zhuǎn)為160位的key。
2.異或距離:
由上述的兩個id,把資源放置在nodeid與key的距離相近的節(jié)點上,就能實現(xiàn)資源的定位。也就是我們可以根據(jù)key去匹配距離相近的nodeid,然后找到在該節(jié)點上與key對應(yīng)的資源value。
其中的距離指的是異或距離。也就是對兩個id進行異或運算,可以是nodeid與nodeid,定位節(jié)點?;蛘遪odeid與key,定位資源。
舉個例子:00110 與 00011 的異或距離為 00101,也就是5。(0⊕0=0,1⊕0=1,1⊕1=0)
3.異或特性:
x ⊕ x = 0,節(jié)點與它本身的異或距離為0。
x ⊕ y > 0 , if x != y,不同節(jié)點異或距離一定大于0。
x ⊕ y =? y ⊕ x,異或距離是對稱的。
x ⊕ y + y ⊕ z >=? x ⊕ z,類似于三角形不等式,第三邊的距離小于等于另外兩邊的距離之和。
x ⊕ y ⊕ y ⊕ z =? x ⊕ z
x + y >= x ⊕ y
4.路由表,與k-bucket:
由于節(jié)點id是一串二進制數(shù),每一位的取值只有0或1,因此我們可以把節(jié)點id表示為二叉樹的形式。以100為例,第一位是1,(從上到下)往右子樹,第二位是0,往左子樹,第三位是0,再往左子樹。最終的葉子節(jié)點即為100。類似于文件夾的路徑。
k-bucket
k-buckst樹形結(jié)構(gòu)
我們把同一個灰色部分的節(jié)點放置在同一個列表,這個列表稱為k-bucket,k桶。k桶中的k指的是每一個列表所能容納的節(jié)點的最大個數(shù)。
劃分k桶是有規(guī)律的。k桶的個數(shù)跟節(jié)點id的位數(shù)有關(guān),假設(shè)節(jié)點id的位數(shù)為n,則最多有n個k桶。第1個k桶中的節(jié)點與本地節(jié)點前n-1位id是相同,第2個k桶中的節(jié)點與本地節(jié)點前n-2位id是相同,以此類推,最后第n個k桶中的節(jié)點與本地節(jié)點第1位id就不一樣了。
所有的k桶合起來也就是一個節(jié)點的路由表。
這里以nodeid為110的節(jié)點為例,共有3個k桶。第i個k桶中異或距離的范圍為[2^i,2^(i+1))。
可以類比為國家的行政區(qū)域劃分來理解。
節(jié)點距離
節(jié)點id為110的路由表
5.協(xié)議消息:
PING — 驗證遠程節(jié)點是否在線。
STORE — 在某個節(jié)點上存儲 key-value 鍵值對。在節(jié)點上存儲資源。
FIND_NODE — 查找節(jié)點,給定一個nodeid,被請求的節(jié)點返回與nodeid相近的k個節(jié)點。
FIND_VALUE — 查找資源,給定一個key,被請求的節(jié)點的nodeid與key相近,并且具有該key,返回與key對應(yīng)的value。
四、BitTorrent基于Kad協(xié)議的實現(xiàn)
KRPC協(xié)議
KRPC是BitTorrent在Kademlia理論基礎(chǔ)之上定義的一個通信消息格式協(xié)議,是由B編碼組成的一個簡單的RPC結(jié)構(gòu),有4種請求:ping、find_node、get_peers 和 announce_peer。一條 KRPC 消息即可能是request,也可能是response
KRPC字典基本組成元素
1. t關(guān)鍵字: 每條消息都包含 t 關(guān)鍵字,它是一個代表了 transaction ID 的字符串。transaction ID 由請求節(jié)點產(chǎn)生,并且回復(fù)中要包含回顯該字段(挑戰(zhàn)-響應(yīng)模型),所以回復(fù)可能對應(yīng)一個節(jié)點的多個請求。transaction ID 應(yīng)當被編碼為一個短的二進制字符串,比如 2 個字節(jié),這樣就可以對應(yīng) 2^16 個請求
2. y關(guān)鍵字: 它由一個字節(jié)組成,表明這個消息的類型。y 對應(yīng)的值有三種情況
1) q 表示請求(請求Queries): q類型的消息它包含 2 個附加的關(guān)鍵字 q 和 a
1.1) 關(guān)鍵字 q: 是字符串類型,包含了請求的方法名字(get_peers/announce_peer/ping/find_node)
1.2) 關(guān)鍵字 a: 一個字典類型包含了請求所附加的參數(shù)(info_hash/id..)
2) r 表示回復(fù)(回復(fù) Responses): 包含了返回的值。發(fā)送回復(fù)消息是在正確解析了請求消息的基礎(chǔ)上完成的,包含了一個附加的關(guān)鍵字 r。關(guān)鍵字 r 是字典類型
2.1) id: 當前節(jié)點id,peer節(jié)點id號或者下一跳DHT節(jié)點
2.2) nodes: ""
2.3) token: token
3) e 表示錯誤(錯誤 Errors): 包含一個附加的關(guān)鍵字 e,關(guān)鍵字 e 是列表類型
3.1) 第一個元素是數(shù)字類型,表明了錯誤碼,當一個請求不能解析或出錯時,錯誤包將被發(fā)送。下表描述了可能出現(xiàn)的錯誤碼
201: 一般錯誤
202: 服務(wù)錯誤
203: 協(xié)議錯誤,比如不規(guī)范的包,無效的參數(shù),或者錯誤的 toke
204: 未知方法
3.2) 第二個元素是字符串類型,表明了錯誤信息
ping報文
檢測節(jié)點是否可達,請求包含一個參數(shù)id,代表該節(jié)點的nodeID。對應(yīng)的回復(fù)也應(yīng)該包含回復(fù)者的nodeID
ping Query = {"t":"aa","y":"q","q":"ping","a":{"id":"abcdefghij0123456789"}}
bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe
Response = {"t":"aa","y":"r","r": {"id":"mnopqrstuvwxyz123456"}}
bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
find_node報文
find_node 被用來查找給定 ID 的DHT節(jié)點的聯(lián)系信息,該請求包含兩個參數(shù)id(代表該節(jié)點的nodeID)和target?;貜?fù)中應(yīng)該包含被請求節(jié)點的路由表中距離target最接近的K個nodeID以及對應(yīng)的nodeINFO。應(yīng)用在定位node的位置,初始化或更新自己的K桶列表。
find_node 請求包含 2 個參數(shù),第一個參數(shù)是 id,包含了請求節(jié)點的ID。第二個參數(shù)是 target,包含了請求者正在查找的節(jié)點的 ID
當一個節(jié)點接收到了 find_node 的請求,他應(yīng)該給出對應(yīng)的回復(fù),回復(fù)中包含 2 個關(guān)鍵字 id(被請求節(jié)點的id) 和 nodes,nodes 是字符串類型,包含了被請求節(jié)點的路由表中最接近目標節(jié)點的 K(8) 個最接近的節(jié)點的聯(lián)系信息(被請求方每次都統(tǒng)一返回最靠近目標節(jié)點的節(jié)點列表K捅)
find_node Query = {"t":"aa","y":"q","q":"find_node","a": {"id":"abcdefghij0123456789","target":"mnopqrstuvwxyz123456"}}
# "id"containing the node ID of the querying node, and"target" containing the ID of the node sought by the queryer.
bencoded = d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e1:q9:find_node1:t2:aa1:y1:qe
Response = {"t":"aa","y":"r","r": {"id":"0123456789abcdefghij","nodes":"def456..."}}
bencoded = d1:rd2:id20:0123456789abcdefghij5:nodes9:def456...e1:t2:aa1:y1:re
get_peers報文(相當于find_value)
1.get_peers 請求包含2 個參數(shù)(id請求節(jié)點ID,info_hash代表torrent文件的infohash,infohash為種子文件的SHA1哈希值,也就是磁力鏈接的btih值)
2. response get_peer:
1) 如果被請求的節(jié)點有對應(yīng) info_hash 的 peers,他將返回一個關(guān)鍵字 values,這是一個列表類型的字符串。每一個字符串包含了"nodeid-ip-port"格式的 peers 信息。關(guān)鍵字 token 都將被返回。token 關(guān)鍵字在今后的 annouce_peer 請求中必須要攜帶。
2) 如果被請求的節(jié)點沒有這個 info_hash 的 peers,那么他將返回關(guān)鍵字 nodes,這個關(guān)鍵字包含了被請求節(jié)點的路由表中離 info_hash 最近的 K 個節(jié)點(我這里沒有該節(jié)點,去別的節(jié)點試試運氣)。
announce_peer 報文(相當于store)
announce_peer: 這個請求用來表明發(fā)出 announce_peer 請求的節(jié)點,正在某個端口下載 torrent 文件
announce_peer 包含 4 個參數(shù)
1. 第一個參數(shù)是 id: 包含了請求節(jié)點的 ID
2. 第二個參數(shù)是 info_hash: 包含了 torrent 文件的 infohash
3. 第三個參數(shù)是 port: 包含了整型的端口號,表明 peer 在哪個端口下載
4. 第四個參數(shù)數(shù)是 token: 這是在之前的 get_peers 請求中收到的回復(fù)中包含的。收到 announce_peer 請求的節(jié)點必須檢查這個 token 與之前我們回復(fù)給這個節(jié)點 get_peers 的 token 是否相同(也就說,所有下載者/發(fā)布者都要參與檢測新加入的發(fā)布者是否偽造了該資源)
如果相同,那么被請求的節(jié)點將記錄發(fā)送 announce_peer 節(jié)點的 IP 和請求中包含的 port 端口號在 peer 聯(lián)系信息中對應(yīng)的 infohash 下,這意味著一個一個事實: 當前這個資源有一個新的peer提供者了,下一次有其他節(jié)點希望或者這個資源的時候,會把這個新的(前一次請求下載資源的節(jié)點)也當作一個peer返回給請求者,這樣,資源的提供者就越來越多,資源共享速度就越來越快。
一個peer正在下載某個資源,意味著該peer有能夠訪問到該資源的渠道,且該peer本地是有這份資源的全部或部分拷貝的,它需要向DHT網(wǎng)絡(luò)廣播announce消息,告訴其他節(jié)點這個資源的下載地址
五、DHT網(wǎng)絡(luò)的其他應(yīng)用
1、以太坊
2、洋蔥網(wǎng)絡(luò)
六、一些數(shù)字比較
為了讓大家能更直觀的了解DHT網(wǎng)絡(luò)的節(jié)點空間容量,我翻了一些數(shù)據(jù)作為比較。
1、DHT網(wǎng)絡(luò)有160bit,可以容納2^160個節(jié)點,也就約等于 10^48個節(jié)點。
2、地球的總?cè)藬?shù)70億,四舍五入100億(10^10)
3、原子核直徑10^-14米。
4、銀河系最長直徑1.7029e+21米。本星系群9.4607e+22米 。室女座超星系團 9.4607e+23(約10^24)米。
那么假如每個人都成為DHT網(wǎng)絡(luò)中的節(jié)點,就只占據(jù)整個網(wǎng)絡(luò)的 10^38分之一;這個尺度就相當于一顆原子核相對于室女座超星系團那么大。哈希碰撞基本不用考慮。
但神奇的是,在那么大的網(wǎng)絡(luò)中,尋找其中任意一點,最多只需要160次find_node就可以完成。這與六度人脈理論異曲同工。
七、留下思考問題
為什么BT協(xié)議實現(xiàn)DHT網(wǎng)絡(luò)要用二叉樹呢?如果用16叉樹會怎樣?
參考資料
總結(jié)
以上是生活随笔為你收集整理的dht网络协议 服务器,概述DHT网络的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爬虫dht
- 下一篇: 使用FFmpeg工具进行推流、拉流、截图