DHT網絡

@(基礎技術)node

如今有一種方法,能夠經過磁力連接,例如magnet:?xt=urn:btih:0482e0811014fd4cb5d207d08a7be616a4672daa,就能夠獲取BT文件。
這個是經過DHT網絡來實現的。
DHT網絡是一個去中心化的,分佈式信息存儲系統。
存儲的信息就是bt文件。算法

1、節點

每一臺電腦,就是一個節點。它既是客戶端,也是服務端。
每一個節點都有一個節點ID,IP地址和端口號(節點進程的端口)。
節點ID由160位的二進制字符串組成,也就是長度爲32的16進制字符串,跟咱們經常使用的md5同樣。
經過異或算法,能夠計算兩個節點ID的距離。例如01和00的異或結果是01,也就是距離是1。json

2、路由表

每一個節點都會保存一個路由表,保存其餘節點的信息,節點信息包括:節點ID,節點的IP地址和端口號。
路由表中,會有多個bucket,例如bucket-1,bucket-2等等。
bucket-i保存的是與自身節點ID距離爲[2^i-1,2^i)的節點信息
每一個nodeid能夠理解爲深度是160的二叉樹,二bucket-i就是自身的葉子的第i個父節點的兄弟節點的全部葉子節點(不太嚴謹)
以下圖:
Alt text服務器

因此i最大值是160。網絡

而爲何要這麼存了?
這樣存是爲了能夠快速找到目標節點N2。
例如自身的節點ID是N1,須要尋找N2的IP和端口號。分佈式

  • 計算N1和N2的距離D
  • 從bucket-D,找一個節點N3,若是N3=N2,就找到了,不然就向N3發送尋找節點N2的請求
  • N3接收到請求後,計算N2和N3的距離D1,從N3的路由表裏面的bucket-D1,找到一個節點N4,返回N4的信息給N1
  • N1收到返回後,若是N4=N2,就找到了,不然繼續向N4發送尋找節點N2的請求。一直遞歸。

由於N2和N3會處於同一個bucket,因此他們的距離D1不會超過D/2,因此每一次循環,得到的節點NN與N2的距離都會比以前的請求縮小1倍。因此時間複雜度是logN。跟二分查找是同樣的。加密

3、信息發佈

當發佈者,須要發佈信息(例如一個bt文件)到DHT網絡。.net

  • 發佈者會計算信息的md5,M1
  • 經過發佈者的路由表,查詢與M1的距離小於等於K的多個節點
  • 向這些節點發送保存信息(Store)的請求,就會把信息存儲在這些節點上

k通常要大於1。否則只會把信息存儲在一個節點上,萬一節點下線,或者退出網絡,就會致使信息不能被找到。線程

4、數據包

節點與節點之間,經過UDP協議,傳輸數據包來通信。
DHT網絡的數據包都是json格式。
必須字段:code

  • t:消息的id。由於是UDP傳輸,因此要帶上消息ID,不要就不知道每一個包對應是哪一個包的回覆。
  • y:數據包的類型,取值能夠是:
    • q,請求包
    • r,回覆包
    • e,錯誤包,其實也是回覆的一種

      1. 請求和回覆包

      請求包必須字段
  • q,請求的類型,
    • ping 嗅探Node是否可用
    • find_node。尋找Node的請求
    • get_peers。尋找有資源的Node
    • announce_peer ,請求下載資源
  • a,請求的參數,類型是json裏面的字典

回覆包必須字段:
*r 回覆的內容,字典

1.1ping

請求包
a包含字段

  • id,請求者的nodeid

包例子

{"t":"aa", "y":"q","q":"ping", "a":{"id":"abcdefghij0123456789"}}

回覆包
r包含字段

  • id 回覆者的nodeid

包例子

{"t":"aa", "y":"r", "r":{"id":"mnopqrstuvwxyz123456"}}

1.2find_node

請求包
a包含字段

  • id,請求者的nodeid
  • target,須要尋找的Node的nodeid

包例子:

{"t":"aa", "y":"q","q":"find_node", "a":{"id":"abcdefghij0123456789","target":"mnopqrstuvwxyz123456"}}

回覆包
r包含字段

  • id 回覆者的nodeid
  • nodes 在回覆者的路由表中,與請求的target 的nodeid最接近的幾個節點的信息,包含節點的ip,端口,nodeid。

包例子

{"t":"aa", "y":"r", "r":{"id":"0123456789abcdefghij", "nodes":"def456..."}}

1.3 get_peers

請求包
a包含字段

  • id,請求者的nodeid
  • info_hash 尋找的資源的hash
  • token 密鑰

包例子

{"t":"aa", "y":"q","q":"get_peers", "a":{"id":"abcdefghij0123456789","info_hash":"mnopqrstuvwxyz123456"}}

回覆包
若是回覆者的路由表中,有存有info_hash資源的節點信息,就返回value,不然返回node,node的值和find_node同樣
r包含字段

  • id 回覆者的nodeid
  • value,擁有info_hash的節點信息
  • nodes 和find_node的nodes同樣

包例子

{"t":"aa", "y":"r", "r":{"id":"abcdefghij0123456789", "token":"aoeusnth","values": ["axje.u", "idhtnm"]}}

1.4 announce_peer

請求包
a包含字段

  • id,請求者的nodeid
  • info_hash 尋找的資源的hash
  • token 密鑰
  • port,下載資源的端口

包例子

{"t":"aa", "y":"q","q":"announce_peer", "a":{"id":"abcdefghij0123456789","info_hash":"mnopqrstuvwxyz123456", "port":6881, "token": "aoeusnth"}}

回覆包
r包含字段

  • id 回覆者的nodeid

包例子

{"t":"aa", "y":"r", "r":{"id":"mnopqrstuvwxyz123456"}}

2. 錯誤包

  • e 列表類型,第一個元素時錯誤id,第二個是錯誤的說明

    {"t":"aa", "y":"e", "e":[201,"A Generic Error Ocurred"]}

錯誤類型有:

  • 201 通常錯誤
  • 202 服務錯誤
  • 203 協議錯誤,好比不規範的包,無效的參數,或者錯誤的token
  • 204 未知方法

5、工做流程

1.初始化

  • 向一個固定的服務器,獲取節點ID,完成冷啓動
  • 不斷向已知的節點發送find_node請求,讓本身的路由表裏面的節點更多

2. 根據磁力連接,獲取信息(bt文件)

  • 獲取磁力連接裏面的md5,轉換爲二進制M1。
  • 經過路由表,獲取與M1距離最近的節點,而後向它們發送announce_peer 請求。若是節點有咱們想要的信息,就會把信息發過來,這樣咱們就獲取到了bt文件了。

6、DHT網絡中收集bt文件的原理

向三個固定服務器發送find_node的請求,target是隨機的nodeid或者是本身的nodeid,N1
服務器返回最接近N1的的3個nodeid的信息,這些信息是一個加密了的,固定協議的字符串,裏面有node的ip,port和nodeid。自身節點把全部的node存儲到路由表
新開一個線程,對node,再發送find_node請求,這時本身的nodeid是隨機的
這樣,就會致使在不少個DHTNode中,都有咱們ip和端口的信息,並且映射到不少不一樣的nodeid
這樣別人去這些DHTNode中尋找bt資源的時候,這些Node就極可能會返回咱們的IP,PORT給別人,那麼別人就會向咱們發送announce_peer的請求,這樣咱們就能拿到bt文件了

  1. 初始化,目的是讓本身的nodeid加入到DHT網絡中,並認識儘可能多的其餘node,放到咱們的路由表。
    1. 生成本身的nodeid。
    2. 向固定的服務器(例如:),發送find_node請求,target是本身的nodeid,這樣,本身的nodeid就會進入到固定服務器的路由表,這樣其餘node想固定服務器發送find_node請求的話,固定服務器就會返回咱們的nodeid給他們,這樣咱們的nodeid就會進入不少其餘Node的路由表了。
    3. 發送給固定服務器的find_node請求中,會返回咱們附近的node的信息,保存到咱們本身的路由表
  2. 接收其餘節點的請求。當咱們加入到DHT網絡中,就會有其餘節點發送請求給咱們。下面的請求處理完後,咱們都把請求者加入到咱們的路由表中。
    1. 當咱們收到ping請求,就返回本身的id給它,表示本身在正常運行。
    2. 當咱們收到find_node請求, 就從咱們的路由表查找離target最近的N個node的信息,返回給它。
    3. 當咱們收到get_peers請求,就從咱們的路由表中查找擁有該資源的peers信息,返回給它。
    4. 當咱們收到announce_peer 請求,就從發送info_hash的資源到對應的端口

7、Bt文件下載原理

當獲得BT文件後,就能夠用bt文件下載器進行文件的下載
BT文件裏面包含

  • tracket地址
  • 目標文件列表,和分塊信息。每一塊是2k的倍數。分塊信息包含每個分塊的索引和MD5
  • BT文件的基本信息,如標題,每一個文件的大小和文件名等

下載流程

  • 下載器請求tracket地址,獲取其餘也在下載該bt文件的節點信息
  • 下載器鏈接其餘節點,告訴自身缺乏的分塊的索引和獲取到對方缺乏的分塊索引
  • 若是自身有分塊1,而對方沒有,就向對方發送分塊1
  • 若是對方有分塊2,而自身沒有,就接收分塊2
  • 接收完一個分塊後,計算md5,而後和bt文件裏面的md5對比,若是正確,就下載完成,不然要從新下載。

因此bt文件的下載過程,並非去中心化的,tracket服務器就是一箇中心化的服務器。
tracket服務器只管理下載節點的信息,並不會存儲文件的具體分塊。因此壓力也比較小。
節點越多,下載的速度越快。

參考

未經容許,請不要轉載

相關文章
相關標籤/搜索