免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1170 | 回复: 0
打印 上一主题 下一主题

BitTorrent Trackerless DHT协议规范V1.0试行草案 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-02-02 03:38 |只看该作者 |倒序浏览
DHT 协议
摘自 BitTorrentDev
BitTorrent 使用一个"分布式sloppy哈希表" (DHT)来为"trackerless"流存储peer联系信息。有效地使每个peer都成了一个tracker,这个协议基于Kademila网络并且在UDP上实现。
请注意本文档中使用的术语,以免混乱。"peer"是在一个TCP端口上监听的一个客户端/服务器,它实现了BitTorrent协议。"节点"是在一个UDP端口上监听的一个客户端/服务器,它实现了分布式哈希表协议。DHT由节点组成,它存储了peer的位置。BitTorrent客户端包含一个DHT节点,这个节点是用来联系DHT中其他节点以得到peer的位置,从而通过BitTorrent协议下载。
内容
·        1 概述
·        2 路由表
·        3 BitTorrent协议扩展
·        4 Torrent文件扩展
·        5 KRPC协议
o        5.1 Contact Encoding
o        5.2 Queries
o        5.3 Responses
o        5.4 Errors
§        5.4.1错误包例子
·        6 DHT请求
o        6.1 ping
§        6.1.1包例子
o        6.2 find_node
§        6.2.1包例子
o        6.3 get_peers
§        6.3.1包例子
o        6.4 announce_peer
§        6.4.1包例子
·        7脚注
概述
每个节点有一个全局唯一的标识符,称为"节点ID"。节点ID是从一个160位空间随机选择的,这个空间同样用来表示BitTorrent infohash。"米制距离"用来比较两个节点ID之间或者一个节点ID和一个infohash之间的"远近"。节点必须维护一个含有少量其它节点联系信息的路由表。ID越靠近节点本身的ID时,路由表越详细。节点知道DHT中很多ID离自己很"近"的节点的联系信息,而离自己非常远的ID的联系信息却很少。
在Kademlia网络中,米制距离是异或计算的,结果视为无符号整数。
distance(A,B) = |A ⊗ B| ,值越小表示越近。
当节点要为流寻找peer时,它使用米制距离来比较那些ID在自己路由表中节点的流的infohash。然后它联系它所知的ID离infohash最近的节点,问它们正在下载这个流的peer的联系信息。如果一个被联系的节点知道下载这个流的peer信息,那个peer的联系信息将随着回复信息被返回。否则,那个被联系的节点必须回复在它路由表中离流的infohash最近的节点的联系信息。最初的节点重复地请求比目标infohash更近的节点直道不能再找到更近的节点为止。查询完了之后,客户端把peer联系信息加入到所有回复节点中ID离流最近的那个节点中。
请求peer的返回值包含一个不透明的值,称之为"令牌"。为了一个节点宣布它所控制的peer正在下载一个流,它必须赠送从同一个被请求的节点收到的令牌给新来的寻找peer的请求。当一个节点试图"宣布"一个流时,被请求的节点核对令牌和发出请求的节点的IP地址。这是为了防止恶意的主机雇用其它主机。由于令牌仅仅由请求节点返回给收到令牌的同一个节点,所以执行未被定义。令牌在被分布之后必须在一个合理数量的时间被接受。BitTorrent执行使用每五分钟变换一次以保持连接秘密的IP地址的SHA1哈希,和接受十分钟以内旧的令牌。
路由表
每个节点维护一个已知的好的节点路由表。路由表中的节点是用来作为在DHT中请求的起始点。路由表中的节点以回复的形式被返回给其它发出请求节点。
不是所有我们学习的的节点都是相等的。一些是"好的"一些不是。使用DHT的许多节点能够发送请求和接受回复,但是不能回复来自其它节点的请求。节点的路由表必须只包含已知的好的节点,这是很重要的。一个好的节点是一个在过去15分钟内回复过其中一个我们的请求的一个节点。一个节点如果在过去15分钟内曾经回复过其中一个我们的请求,而且发送过一个请求给我们。一个节点静止15分钟以后,变成可疑的。当未能回复连续多个请求时节点变成坏的。我们知道好的节点被给于高于未知状态的节点优先权。
路由表覆盖了ID空间从0到2^160的全部节点。路由表被细分为"桶",每个桶覆盖一部分ID空间。一个空表有一个桶,其ID空间范围是min=0,max=2^160。当一个ID为"N"的节点被插入到表中时,它被放置在min ", ], ["", ], ...] nodes = [["127.0.0.1", 6881], ["your.router.node", 4804]]
KRPC协议
KRPC协议是一个简单的RPC机制,由在UDP上发送的bencode编码的字典组成。发出单个请求包,单个包作为回复。没有重试。有三种消息类型: query,response,和error。在DHT协议中,有四种query: ping,find_node,get_peers,和announce_peer。
一个KRPC消息是单个字典有和每个消息一样的两个关键字,不同消息类型还有附加的关键字。每个消息有一个关键字"t",和一个单字符串值称为transaction ID。这个transaction ID 是请求节点产生的,在回复中被反射,所以回复可能关联多个给同一个节点的请求。包含在每个KRPC信息里的另一个关键字是"y",和一个单字符值描述了消息类型。关键字"y"的值是以下其中一个:"q" 代表请求,"r"代表回复,或者"e"代表错误。
CONTACT ENCODING
peer的联系信息以一个6字节的字符串编码。也就是"联系IP-地址/端口信息",网络字节排序的4字节的IP地址和网络字节排序2字节端口在连接在最后。
节点的联系信息以一个26字节的字符串编码。也就是"联系节点信息",网络字节顺序的20字节的节点ID,还有联系IP-地址/端口信息连接在最后。
QUERIES
请求,也就是KRPC消息字典和一个关键字"y",值是"q",包含两个附加关键字:"q"和"a"。关键字"q"有一个字符串值包含请求的方法名。关键字"a"有一个字典值包含请求的 名字参数。
RESPONSES
回复,也就是KRPC消息字典和一个"y",值是"r",包含一个附加关键字"r"。"r"的值是一个字典包含着返回值。回复消息在请求完成的基础上被发送。
ERRORS
错误,也就是KRPC消息字典和一个"y",值是"e",包含一个附加关键字"e"。"e"的值是一个列表。第一个元素是一个整数,它回复了错误代码。第二个元素是一个字符串包含错误信息。当一个请求不能被履行的时候发送错误。以下表格描述了可能的错误代码:
201        一般错误
202        服务器错误
203        协议错误,例如畸形包,无效参数,坏令牌
204        方法未知
错误包例子
generic error = {'t':0, 'y':'e', 'e':[201, "A Generic Error Ocurred"]} bencoded = d1:eli201e23:A Generic Error Ocurrede1:ti0e1:y1:ee
DHT 请求
所有请求有一个"id"关键字,它的值包含了发出请求节点的节点ID。所有回复有一个"id"关键字,它的值包含了发出回复节点的节点ID。
PING
最基础的请求是一个ping。"q" = "ping",一个ping请求有一个参数,"id",它的值是一个20字节的字符串,包含网络字节排序的发送者的节点ID。一个ping的适当回复有一个关键字"id",包含发出回复的节点的节点ID。
arguments: {"id" : ""} response: {"id" : ""}
包例子
ping Query = {"t":"0", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}} bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t1:01:y1:qe
Response = {"t":"0", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}} bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t1:01:y1:re
FIND_NODE
find node用来找给出ID的节点的联系信息。"q" == "find_node",一个find_node请求有两个参数,"id"包含请求节点的节点ID,"target"包含请求者要寻找的节点的ID。当一个节点收到了一个find_node请求,它应该回复一个关键字"nodes"和一个包含目标节点的联系节点信息的字符串,或者在它们自己的路由表中的K(8)最近的好的节点。
arguments: {"id" : "", "target" : ""} response: {"id" : "", "nodes" : ""}
包例子
find_node Query = {'t':0, 'y':'q', 'q':'find_node', 'a': {'id':'abcdefghij0123456789', 'target':'mnopqrstuvwxyz123456'}} bencoded = d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e1:q9:find_node1:ti0e1:y1:qe
Response = {'t':0, 'y':'r', 'r': {'id':'0123456789abcdefghij', 'nodes': 'def456...'}} bencoded = d1:rd2:id20:0123456789abcdefghij5:nodes9:def456...e1:ti0e1:y1:re
GET_PEERS
get peers联合一个流infohash。"q" = "get_peers",一个get_peers请求有两个参数,"id"包含发出请求节点的节点ID,"info_hash"包含流的info_hash。如果那个被请求的节点有适合info_hash的peer,它们将包含在一个关键字"values"中被返回,"values"的值是一个单字符串列表,由包含"compact"格式的peer信息的连接在一起组成。如果那个被请求的节点没有适合info_hash的peer,一个关键字"nodes"被返回,它包含了在被请求的节点的路由表中最接近请求提供的info_hash的节点K。无论那种情况一个"token"关键字也包含在返回值中。令牌的值是一个将来的announce_peer 请求中用到的的一个需要的参数。
arguments: {"id" : "", "info_hash" : ""} response: {"id" : "", "values" : [""]} or: {"id" : "", "nodes" : ""}
包例子
get_peers Query = {'t':0, 'y':'q', 'q':'get_peers', 'a': {'id':'abcdefghij0123456789', 'info_hash':'mnopqrstuvwxyz123456'}} bencoded = d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e1:q9:get_peers1:ti0e1:y1:qe
Response with peers = {'t':0, 'y':'r', 'r': {'id':'abcdefghij0123456789', 'token':'aoeusnth', 'values': ['axje.uidhtnmbrl']}} bencoded = d1:rd2:id20:abcdefghij01234567895:token8:aoeusnth6:valuesl15:axje.uidhtnmbrlee1:ti0e1:y1:re
Response with closest nodes = {'t':0, 'y':'r', 'r': {'id':'abcdefghij0123456789', 'token':'aoeusnth', 'nodes': 'def456...'}} bencoded = d1:rd2:id20:abcdefghij01234567895:nodes9:def456...5:token8:aoeusnthe1:ti0e1:y1:re
ANNOUNCE_PEER
宣布控制发出请求的节点的那个peer正在一个端口上下载那个一个流。announce_peer有四个参数:"id"包含发出请求节点的节点ID,"info_hash"包含流的infohash,"port"包含作为一个整数的端口,还有给前一个get_peers请求的回复中的"token"。被请求的节点必须检验令牌是以前发送给和发出请求的节点一样的IP地址。然后被请求的节点应该把那个发出请求的节点的IP地址和infohash中提供的端口号存储在它的peer联系信息存档中。
arguments: {"id" : "", "info_hash" : "", "port" : , "token" : ""} response: {"id" : ""}
包例子
announce_peers Query = {'t':0, 'y':'q', 'q':'announce_peers', 'a': {'id':'abcdefghij0123456789', 'info_hash':'mnopqrstuvwxyz123456', 'port' : 6881, 'token' : 'aoeusnth'}} bencoded = d1:ad2:id20:abcdefghij01234567899:info_hash20:
mnopqrstuvwxyz1234564:porti6881e5:token8:aoeusnthe1:q14:announce_peers1:ti0e1:y1:qe
Response = {"t":"0", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}} bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t1:01:y1:re
脚注
1.        "Kademlia: A Peer-to-peer Information System Based on the XOR Metric",
Petar Maymounkov and David Mazieres,
2.        Use SHA1 and plenty of entropy to ensure a unique ID

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/10423/showart_241732.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP