Firefox 3
昵称:neoragex2002
园龄:7年2个月
粉丝:11
关注:1

搜索

 

常用链接

随笔分类

文章分类

博客链接

站点链接

最新评论

阅读排行榜

评论排行榜

前两天在网上看到世界知名的电骡服务器Razorback 2被查封、4人被拘禁的消息,深感当前做eMule / BitTorrent等P2P文件交换软件的不易。以分布式哈希表方式(DHT,Distributed Hash Table)来代替集中索引服务器可以说是目前可以预见到的为数不多的P2P软件发展趋势之一,比较典型的方案主要包括:CAN、CHORD、Tapestry、Pastry、Kademlia和Viceroy等,而Kademlia协议则是其中应用最为广泛、原理和实现最为实用、简洁的一种,当前主流的P2P软件无一例外地采用了它作为自己的辅助检索协议,如eMule、Bitcomet、Bitspirit和Azureus等。鉴于Kademlia日益增长的强大影响力,今天特地在blog里写下这篇小文,算是对其相关知识系统的总结。


1. Kademlia简述

Kademlia(简称Kad)属于一种典型的结构化P2P覆盖网络(Structured P2P Overlay Network),以分布式的应用层全网方式来进行信息的存储和检索是其尝试解决的主要问题。在Kademlia网络中,所有信息均以<key, value>的哈希表条目形式加以存储,这些条目被分散地存储在各个节点上,从而以全网方式构成一张巨大的分布式哈希表。我们可以形象地把这张哈希大表看成是一本字典:只要知道了信息索引的key,我们便可以通过Kademlia协议来查询其所对应的value信息,而不管这个value信息究竟是存储在哪一个节点之上。在eMule、BitTorrent等P2P文件交换系统中,Kademlia主要充当了文件信息检索协议这一关键角色,但Kad网络的应用并不仅限于文件交换。下文的描述将主要围绕eMule中Kad网络的设计与实现展开。


2. eMule的Kad网络中究竟存储了哪些信息?

只要是能够表述成为<key, value>字典条目形式的信息Kad网络均能存储,一个Kad网络能够同时存储多张分布式哈希表。以eMule为例,在任一时刻,其Kad网络均存储并维护着两张分布式哈希表,一张我们可以将其命名为关键词字典,而另一张则可以称之为文件索引字典。

a. 关键词字典:主要用于根据给出的关键词查询其所对应的文件名称及相关文件信息,其中key的值等于所给出的关键词字符串的160比特SHA1散列,而其对应的value则为一个列表,在这个列表当中,给出了所有的文件名称当中拥有对应关键词的文件信息,这些信息我们可以简单地用一个3元组条目表示:(文件名,文件长度,文件的SHA1校验值),举个例子,假定存在着一个文件“warcraft_frozen_throne.iso”,当我们分别以“warcraft”、“frozen”、“throne”这三个关键词来查询Kad时,Kad将有可能分别返回三个不同的文件列表,这三个列表的共同之处则在于它们均包含着一个文件名为“warcraft_frozen_throne.iso”的信息条目,通过该条目,我们可以获得对应iso文件的名称、长度及其160比特的SHA1校验值。

b. 文件索引字典:用于根据给出的文件信息来查询文件的拥有者(即该文件的下载服务提供者),其中key的值等于所需下载文件的SHA1校验值(这主要是因为,从统计学角度而言,160比特的SHA1文件校验值可以唯一地确定一份特定数据内容的文件);而对应的value也是一个列表,它给出了当前所有拥有该文件的节点的网络信息,其中的列表条目我们也可以用一个3元组表示:(拥有者IP,下载侦听端口,拥有者节点ID),根据这些信息,eMule便知道该到哪里去下载具备同一SHA1校验值的同一份文件了。


3. 利用Kad网络搜索并下载文件的基本流程是怎样的?

基于我们对eMule的Kad网络中两本字典的理解,利用Kad网络搜索并下载某一特定文件的基本过程便很明白了,仍以“warcraft_frozen_throne.iso”为例,首先我们可以通过warcraft、frozen、throne等任一关键词查询关键词字典,得到该iso的SHA1校验值,然后再通过该校验值查询Kad文件索引字典,从而获得所有提供“warcraft_frozen_throne.iso”下载的网络节点,继而以分段下载方式去这些节点下载整个iso文件。

在上述过程中,Kad网络实际上所起的作用就相当于两本字典,但值得再次指出的是,Kad并不是以集中的索引服务器(如华语P2P源动力、Razorback 2、DonkeyServer 等,骡友们应该很熟悉吧)方式来实现这两本字典的存储和搜索的,因为这两本字典的所有<key, value>条目均分布式地存储在参与Kad网络的各节点中,相关文件信息、下载位置信息的存储和交换均无需集中索引服务器的参与,这不仅提高了查询效率,而且还提高了整个P2P文件交换系统的可靠性,同时具备相当的反拒绝服务攻击能力;更有意思的是,它能帮助我们有效地抵制FBI的追捕,因为俗话说得好:法不治众…看到这里,相信大家都能理解“分布式信息检索”所带来的好处了吧。但是,这些条目究竟是怎样存储的呢?我们又该如何通过Kad网络来找到它们?不着急,慢慢来。


4. 什么叫做节点的ID和节点之间的距离?

Kad网络中的每一个节点均拥有一个专属ID,该ID的具体形式与SHA1散列值类似,为一个长达160bit的整数,它是由节点自己随机生成的,两个节点拥有同一ID的可能性非常之小,因此可以认为这几乎是不可能的。在Kad网络中,两个节点之间距离并不是依靠物理距离、路由器跳数来衡量的,事实上,Kad网络将任意两个节点之间的距离d定义为其二者ID值的逐比特二进制和数,即,假定两个节点的ID分别为a与b,则有:d=a XOR b。在Kad中,每一个节点都可以根据这一距离概念来判断其他节点距离自己的“远近”,当d值大时,节点间距离较远,而当d值小时,则两个节点相距很近。这里的“远近”和“距离”都只是一种逻辑上的度量描述而已;在Kad中,距离这一度量是无方向性的,也就是说a到b的距离恒等于b到a的距离,因为a XOR b==b XOR a


5. <key, value>条目是如何存储在Kad网络中的?

从上文中我们可以发现节点ID与<key, value>条目中key值的相似性:无论是关键词字典的key,还是文件索引字典的key,都是160bit,而节点ID恰恰也是160bit。这显然是有目的的。事实上,节点的ID值也就决定了哪些<key, value>条目可以存储在该节点之中,因为我们完全可以把某一个<key, value>条目简单地存放在节点ID值恰好等于条目中key值的那个节点处,我们可以将满足(ID==key)这一条件的节点命名为目标节点N。这样的话,一个查找<key, value>条目的问题便被简单地转化成为了一个查找ID等于Key值的节点的问题。

由于在实际的Kad网络当中,并不能保证在任一时刻目标节点N均一定存在或者在线,因此Kad网络规定:任一<key, value>条目,依据其key的具体取值,该条目将被复制并存放在节点ID距离key值最近(即当前距离目标节点N最近)的k个节点当中;之所以要将<key, value>重复保存k份,这完全是考虑到整个Kad系统稳定性而引入的冗余;这个k的取值也有讲究,它是一个带有启发性质的估计值,挑选其取值的准则为:“在当前规模的Kad网络中任意选择至少k个节点,令它们在任意时刻同时不在线的几率几乎为0”;目前,k的典型取值为20,即,为保证在任何时刻我们均能找到至少一份某<key, value>条目的拷贝,我们必须事先在Kad网络中将该条目复制至少20份。

由上述可知,对于某一<key, value>条目,在Kad网络中ID越靠近key的节点区域,该条目保存的份数就越多,存储得也越集中;事实上,为了实现较短的查询响应延迟,在条目查询的过程中,任一条目可被cache到任意节点之上;同时为了防止过度cache、保证信息足够新鲜,必须考虑<key, value>条目在节点上存储的时效性:越接近目标结点N,该条目保存的时间将越长,反之,其超时时间就越短;保存在目标节点之上的条目最多能够被保留24小时,如果在此期间该条目被其发布源重新发布的话,其保存时间还可以进一步延长。


6. Kad网络节点需要维护哪些状态信息?

在Kad网络中,每一个节点均维护了160个list,其中的每个list均被称之为一个k-桶(k-bucket),如下图所示。在第i个list中,记录了当前节点已知的与自身距离为2^i~2^(i+1)的一些其他对端节点的网络信息(Node ID,IP地址,UDP端口),每一个list(k-桶)中最多存放k个对端节点信息,注意,此处的k与上文所提到的复制系数k含义是一致的;每一个list中的对端节点信息均按访问时间排序,最早访问的在list头部,而最近新访问的则放在list的尾部。

k-桶中节点信息的更新基本遵循Least-recently Seen Eviction原则:当list容量未满(k-桶中节点个数未满k个),且最新访问的对端节点信息不在当前list中时,其信息将直接添入list队尾,如果其信息已经在当前list中,则其将被移动至队尾;在k-桶容量已满的情况下,添加新节点的情况有点特殊,它将首先检查最早访问的队首节点是否仍有响应,如果有,则队首节点被移至队尾,新访问节点信息被抛弃,如果没有,这才抛弃队首节点,将最新访问的节点信息插入队尾。可以看出,尽可能重用已有节点信息、并且按时间排序是k-桶节点更新方式的主要特点。从启发性的角度而言,这种方式具有一定的依据:在线时间长一点的节点更值得我们信任,因为它已经在线了若干小时,因此,它在下一个小时以内保持在线的可能性将比我们最新访问的节点更大,或者更直观点,我这里再给出一个更加人性化的解释:MP3文件交换本身是一种触犯版权法律的行为,某一个节点反正已经犯了若干个小时的法了,因此,它将比其他新加入的节点更不在乎再多犯一个小时的罪……-_-b

由上可见,设计采用这种多k-bucket数据结构的初衷主要有二:a. 维护最近-最新见到的节点信息更新;b. 实现快速的节点信息筛选操作,也就是说,只要知道某个需要查找的特定目标节点N的ID,我们便可以从当前节点的k-buckets结构中迅速地查出距离N最近的若干已知节点。


7. 在Kad网络中如何寻找某特定的节点?

已知某节点ID,查找获得当前Kad网络中与之距离最短的k个节点所对应的网络信息(Node ID,IP地址,UDP端口)的过程,即为Kad网络中的一次节点查询过程(Node Lookup)。注意,Kad之所以没有把节点查询过程严格地定义成为仅仅只查询单个目标节点的过程,这主要是因为Kad网络并没有对节点的上线时间作出任何前提假设,因此在多数情况下我们并不能肯定需要查找的目标节点一定在线或存在。

整个节点查询过程非常直接,其方式类似于DNS的迭代查询:
a. 由查询发起者从自己的k-桶中筛选出若干距离目标ID最近的节点,并向这些节点同时发送异步查询请求;
b .被查询节点收到请求之后,将从自己的k-桶中找出自己所知道的距离查询目标ID最近的若干个节点,并返回给发起者;
c. 发起者在收到这些返回信息之后,再次从自己目前所有已知的距离目标较近的节点中挑选出若干没有请求过的,并重复步骤1;
d. 上述步骤不断重复,直至无法获得比查询者当前已知的k个节点更接近目标的活动节点为止。
e. 在查询过程中,没有及时响应的节点将立即被排除;查询者必须保证最终获得的k个最近节点都是活动的。

简单总结一下上述过程,实际上它跟我们日常生活中去找某一个人打听某件事是非常相似的,比方说你是个Agent Smith,想找小李(key)问问他的手机号码(value),但你事先并不认识他,你首先肯定会去找你所认识的和小李在同一个公司工作的人,比方说小赵,然后小赵又会告诉你去找与和小李在同一部门的小刘,然后小刘又会进一步告诉你去找和小李在同一个项目组的小张,最后,你找到了小张,哟,正好小李出差去了(节点下线了),但小张恰好知道小李的号码(cache),这样你总算找到了所需的信息。在节点查找的过程中,“节点距离的远近”实际上与上面例子中“人际关系的密切程度”所代表的含义是一样的。

最后说说上述查询过程的局限性:Kad网络并不适合应用于模糊搜索,如通配符支持、部分查找等场合,但对于文件共享场合来说,基于关键词的精确查找功能已经基本足够了(值得注意的是,实际上我们只要对上述查找过程稍加改进,并可以令其支持基于关键词匹配的布尔条件查询,但仍不够优化)。这个问题反映到eMule的应用层面来,它直接说明了文件共享时其命名的重要性所在,即,文件名中的关键词定义得越明显,则该文件越容易被找到,从而越有利于其在P2P网络中的传播;而另一方面,在eMule中,每一个共享文件均可以拥有自己的相关注释,而Comment的重要性还没有被大家认识到:实际上,这个文件注释中的关键词也可以直接被利用来替代文件名关键词,从而指导和方便用户搜索,尤其是当文件名本身并没有体现出关键词的时候。


8. 在Kad网络中如何存储和搜索某特定的<key, value>条目?

从本质上而言,存储、搜索某特定<key, value>条目的问题实际上就是节点查找的问题。当需要在Kad网络中存储一个条目时,可以首先通过节点查找算法找到距离key最近的k个节点,然后再通知它们保存<key, value>条目即可。而搜索条目的过程则与节点查询过程也是基本类似,由搜索发起方以迭代方式不断查询距离key较近的节点,一旦查询路径中的任一节点返回了所需查找的value,整个搜索的过程就结束。为提高效率,当搜索成功之后,发起方可以选择将搜索到的条目存储到查询路径的多个节点中,作为方便后继查询的cache;条目cache的超时时间与节点-key之间的距离呈指数反比关系。


9. 一个新节点如何首次加入Kad网络?

当一个新节点首次试图加入Kad网络时,它必须做三件事,其一,不管通过何种途径,获知一个已经加入Kad网络的节点信息(我们可以称之为节点I),并将其加入自己的k-buckets;其二,向该节点发起一次针对自己ID的节点查询请求,从而通过节点I获取一系列与自己距离邻近的其他节点的信息;最后,刷新所有的k-bucket,保证自己所获得的节点信息全部都是新鲜的。


参考文献

1. Kademlia: A Peer-to-peer Information System Based on the XOR Metric, Petar Maymounkov, Proc. IPTPS 2002
2. 到底什么是Kad, http://bbs.5qzone.net/read.php?tid=321431
3. Kademlia原理介绍, http://www.edonkey2000.cn/bbs/viewthread.php?tid=58238

posted on 2006-02-25 20:01 neoragex2002 阅读(7830) 评论(84) 编辑 收藏

FeedBack:
"7. 在Kad网络中如何寻找某特定的节点?
...
d. 上述步骤不断重复,直至无法获得比查询者当前已知的k个节点更接近目标的活动节点为止。
"
这 k 个节点中包不包含查询发起都本身呢?: )
有点钻牛角尖,莫怪,小的有这癖好

 回复 引用   
#2楼[楼主2006-04-06 17:49 neoragex2002      
当然无需包括发起者自己:)首先,如果信息本身就是存储在发起者自己身上的,那么整个kad网络查询的过程就可以省了;其次,整个kad查询过程是一个逐步逼近的迭代过程,查找k桶,获得较近节点->询问较近节点,获得更近的节点->更新k桶,获得更近节点->.... 直到查到所需信息为止;如果发现无论怎么样都无法获得比当前已知节点更接近的节点、并且无法在查询路径上获得所需信息的cache,这时查找就终止了,因为kad网上不存在被查找的信息,如果把自己又算进去,那岂不成死循环了?呵呵
 回复 引用 查看   
谢谢回答!
我对kademlia的理解又进了一层 : )

 回复 引用   
#4楼 2006-04-27 15:41 robben[未注册用户]

该算法的主要问题在于:
1、任何一个节点加入网络后,网络中所有节点都需要更新自己的路由表。
2、所有节点都要注意实时监测其他节点是否不告而别了(如网络断掉、死机、强制退出等)。
如果想把所有的p2p用户以这种structured结构组织在一起(如果分成不同子网,则还是需要server,这个server又成了打击对象),网络开销过于惊人。楼主也说明采用了它只是作为辅助检索协议,如有兴趣,可以研究一下该辅助协议的命中率到底有多少。

 回复 引用   
#5楼[楼主2006-04-27 18:27 neoragex2002      
@robben
re: 1、任何一个节点加入网络后,网络中所有节点都需要更新自己的路由表。
不是这样的。一个节点新加入时,只有与其距离较近的若干节点需要将其添加到k-桶中,而不是所有节点。

re: 2、所有节点都要注意实时监测其他节点是否不告而别了
不需要实时监测。Kademlia实际上是一种具有容错能力的查找协议,就是目标节点死掉了、down了也没关系,因为它本身就考虑了信息冗余的问题,文中已经说了:存储信息时,存储在“能够找到的距离最近的“节点上和cache在查找路径上,而不必”正好“存放在对应的目标节点之上。查找时情况也一样,不一定非要在正好对应的目标节点中获取到所需信息。一旦目标节点上线,其邻居自然会将本应其保存的信息存放到它身上。

re: 网络开销过于惊人、协议的命中率多少
这个工作其实也不必自己来做,去verycd.com注册个账号,然后听听坛子里面的老驴友们怎么说,emule软件附带详细的统计功能,能够将kad协议开销和实际数据流量分开记帐,现在BitComet也用了DHT,用相当长一段时间的emule/BC之后,自然能够获得一个评判,就我的印象而言,效果是令人满意的,其开销是值得的。

re: 如果分成不同子网,这个server又成了打击对象
kad协议是基于应用层的完全分布式协议的,不需要server,之所以目前只作为辅助索引协议,是因为大家都希望它能够在应用中进一步成熟,既然它与索引服务器相结合能够使大家更加受益,那么何乐而不为?现在形势还没严峻到只能用DHT共享的时候。而Kad网络的随机化和隐私化问题,在现在的框架内也是不难解决的。

至于子网互连路由器是否被封,这是网络层的事,而不是kad单方面考虑的问题。因知识产权问题而直接打压网络层,那就不止是电驴玩完了,啥浏览网页、收发邮件、网络游戏、IM啥的都得来垫背,大伙服务质量一起降低,这无异于竭泽而渔,这种针对性不强、不准的打压政策只会被人嘲笑,反倒更加得不偿失。


 回复 引用 查看   
#6楼 2006-04-28 17:06 robben[未注册用户]
该方法类似于最简单的DHT模型加cache,但却首先被实用化了,改进型DHT的chord、pastry反而停留在学校阶段,真是晕啊
 回复 引用   
#7楼[楼主2006-04-28 22:10 neoragex2002      
@robben
呵呵,恐怕又搞错了吧,kad貌似比chord、pastry更原始更简单?在chord和pastry都是2001提出来的,其paper里面都没有与kademlia的比较;而在kademlia的论文于2002年发表,其中却是有与chord/pastry的比较论述的,其作者明确指出kad适用前提比chord宽泛、查询收敛性能比pastry优越。

简洁、有效就是美,这点在kad身上体现得再明显不过,而且越便于实现就越容易形成影响力,对吧?当然,kad与emule应用接合得比较紧密,这也促进其普及的一个重要原因吧。

 回复 引用 查看   
#8楼 2006-04-29 15:22 robben[未注册用户]
太好了,跟你讨论一下很有收获。
因为觉得不是很复杂,自己想尝试实现一下kademlia。但是The eMule Protocol Specification中好像还没有收入kad协议,不知道哪里可以找到具体的相关协议呢?

 回复 引用   
#9楼[楼主2006-04-29 20:30 neoragex2002      
@robben
目前的kad协议实现普遍兼容性还不够,没有一个比较权威的实现标准。你可以参考一下文献[1],或者是KadC、emule的源码。
http://kadc.sourceforge.net/
http://sourceforge.net/projects/emule

 回复 引用 查看   
#10楼[楼主2006-06-16 15:23 neoragex2002      
不必,在BT里面,DHT只负责发布文件交换参与者的location,而其参与者具体拥有哪些数据块可供下载,这由BT中标准的Peer Wire Protocol解决。也就是说,找到拥有你所感兴趣的文件的peer,用DHT;找到peer以后,了解他是不是拥有你所需要的数据块,用BT自带的点对点通信协议。目前DHT的发布粒度只到文件级,如果精确到数据块级,将导致kad控制开销在流量中所占比重过大,划不来。

16 Jun 2006 12:58:49 +0800, zupeng@gmail.com <zupeng@gmail.com>:
> 看了您对Kademlia的分析,受益匪浅.
> 有个问题一直不解,能否请教?
> BT中的协同下载是在每个用户下载的同时,通过Tracker分配,每个节点交换各自已经下载的片断;
> 那DHT中某个正在下载文件的节点会将已经下载的文件片断也同时共享到DHT网络中供他人下载吗?
> ________________________________
> 发送者:Robert
> Email:zupeng@gmail.com
> 发送时间:2006-06-16 12:58
> 消息来自:http://neoragex2002.cnblogs.com/

 回复 引用 查看   
#11楼[楼主2006-06-16 16:44 neoragex2002      
no,peer一旦参与bt,即可将自己发布到DHT,对于bt这种功利性很强的p2p应用来说,下载完了再发布已经太晚了。我建议你了解一下bt的peer wire protocol,里面有个bitfields专门负责通告对方自己拥有哪些块。

至于开销量级有多大,要视应用方式、共享文件数、节点数、信息刷新率、冗余率等诸多因素而定,作者原文没有明确说明,他更关注的是收敛速度和查询效率。不过你可以通过emule自己做做试验,emule具备相应统计功能。只用kad的emule控制开销给我的印象还是比较大的,因为需要周期性的发布和刷新来避免信息陈腐。

至于节点加入退出是不是要通知全网,答案是"are not necessary explicitly",其他人已经问过了,理由见blog中的其他回复。

在 06-6-16,Robert<zupeng@gmail.com> 写道:
> 非常感谢!
> 那您的意思就是说,只有完全下载了整个文件的节点才会将自己的信息发布到DHT网络中供其它用户下载使用.
> 这样理解对吗?
> 另外,在Kademlia协议中,每个节点动态加入和退出网络造成的网络维护开销会有多大啊?他们加入和退出需要通知全网所有节点吗?
> 我分析过Chord,知道每个节点stablization一下,开销还是很大的,达到O(log 2 N).
>
> 请赐教 :)
>
> Robert

 回复 引用 查看   
>第8节:一旦查询路径中的任一节点返回了所需查找的value,
>整个搜索的过程就结束。

实际上的应用大概没这样做吧。文件共享的搜索都是为了找source,越多越好,怎么可能找到一个就罢手。所以,我认为kademlia的Cache方法根本不实用。

 回复 引用   
#13楼[楼主2006-07-11 17:04 neoragex2002      
@善解人衣

你的理解不对,而且看得不够仔细啊....:) 事实是节点存储了一个对应于文件hash的source列表,而不仅仅只是一个source单值。也就是说,文件索引字典中,key是文件hash,value则是对应source的一个列表。cache也针对的是source列表。一次查询和cache的目的都是为了提高效率。这其实在第3节中已经说得很明白了:"从而获得所有提供....下载的网络节点"

 回复 引用 查看   
谢谢这么快的回复,我再来质疑。
首先,Publish过程中,value里基本上是一个source(做Publish的Peer自己
)吧。

第一步,一个新Peer A加入网络。
第二步,Peer B, Publish 到A上一个文件X, hash(X) = A
这时,A上对X这个文件只有一个source B吧
第三步,Peer C,找文件X,找到A,A却只给了一个文件,
因为“一旦找到value整个搜索的过程就结束”,结果Peer C只找到一个source B.

你认为以上合理吗?

 回复 引用   
#15楼[楼主2006-07-11 18:12 neoragex2002      
@善解人衣

完全合理。如果在第二步和第三步之间存在一个peer Z,它publish了一个哈希值与X完全一样的文件,那么Z最终也会存到A节点上的,对文件索引字典中A所存储的信息而言,key=hash(X),而value=(A,Z)。尽管信息归并需要时间,但最终收敛状态下一次查询就足够了。

第三步,Peer C,找文件X,找到A,A会将(A,Z)给它,而不是仅仅一个A。 即使由于Z publish的延迟,C第一次只得到了A,那么再过一段时间它再查一次的话,C终将得到所有source,而这个“再次查询”频率可以很高也可以很低,视下载优先级、网络规模和收敛速度而定。现在的emule正是这么做的。

如第8节述,对于emule具体实现而言,kad网络中存储的<key, value>是一个单值条目,节点将负责source信息的归并,而搜索返回的却是当前收敛状态下的列表条目,这是不是很容易理解?

 回复 引用 查看   
呵呵,emule可没有,“旦查询路径中的任一节点返回了所需查找的value, 整个搜索的过程就结束。 ”哦。

 回复 引用   
#17楼[楼主2006-07-11 18:19 neoragex2002      
@善解人衣

如果你认为一次查询返回的source数量足够了,那当然可以这么做。你的关键论点是一次查询只返回一个source,这是一个显而易见的错误。

 回复 引用 查看   
emule也没有:"为提高效率,当搜索成功之后,发起方可以选择将搜索到的条目存储到查询路径的多个节点中,作为方便后继查询的cache"

overnet实现本就偏离Petar 的Paper,emule的kademlia原来作者Barry Dunne,根据Petar的java代码写的emule的kademlia,突然有一天Barry Dunne消失了,后来的emule team一时找不到方向,很久之后才检起来和Petar的Paper出入就更大了。

 回复 引用   
>你的关键论点是一次查询只返回一个source,这是一个显而易见的错误。

OK,我写错了,关键我的质疑仍然是:“一旦查询路径中的任一节点返回了所需查找的value, 整个搜索的过程就结束。”

别的DHT不知道,但emule肯定没这样做,我记得是要查询到最大N个Peer或某个最大结果数。

 回复 引用   
#20楼[楼主2006-07-11 18:34 neoragex2002      
@善解人衣
呵呵,paper只是一种seminal idea,任何实现的偏离都是可能且容许的,因为你不能阻止实现者们发挥他们自己的创造力,但idea本身却是共性的东西,所以值得我们参考和借鉴。

如果emule没有做cache,那么自然会有想做的人去做,在适当的场合,以适当的方式,P2P本不是一个复杂概念,死抠实现上的details没有意义。

 回复 引用 查看   
#21楼[楼主2006-07-11 18:41 neoragex2002      
@善解人衣
18:12的答复就是我要说的。Ok, you're right,我那句话再加上一个定语“在足够收敛的状态下”是不是就清楚了? :) 言止于此,有疑问欢迎讨论。

 回复 引用 查看   
你们好
你们说了一大堆我也看不懂,我是个不懂电脑的人。我用的是vagaa软件,下载速度太慢,起初我还以为是我网速慢,现在我把速率换成1兆的还是慢特别是下到最后就下不了了,总是等待或连接中,不知道是为什么。
请高人指点。我的邮箱huxiaowei.com@163.com
不胜感激
谢谢。。。。。

 回复 引用   
#23楼[楼主2006-09-18 15:00 neoragex2002      
来信,贴出来给大家参考:

neoragex2002你好! 我有些疑问,具体疑问如下:
1.关键词字典条目中的key为160位的SHA1散列值(可以为字符串吗?),文件索引字典中的key对应的value 中的节点ID也是一个SHA1的散列值(160位整数),那么key能不能为字符串,我的意思是说能不能是包含x,y,z等这样的字符串.
2.节点的ID是由自己随机生成的,每次登录时需要再次生成吗?节点ID生成的算法是什么?使用什么来作SHA1运算得到节点ID? 每次计算的结果是不是一样?
3.kad网络是无中心索引服务的,那么当节点加入KAD网络时,它必须要知道一个其他节点的ID,这个ID怎么得到?

回复:
1. key只能用散列生成,而且必须尽量保证不重复.这是基本原则.如果一定要字符串,很简单,对key进行base64编码就可以了.
2. 节点ID只需生成一次.只要是冲突概率小的算法都可以,也可以通过ID长度来保证其重复的小概率.用时间相关/硬件相关的随机数.每次计算结果不一样,由于关系到节点信誉,不建议多次生成ID
3. 有很多简单的方式,比如由kad网管提供一个或者多个专供bootrap的众所周知节点等

 回复 引用 查看   
最近在看kademlia的paper,看了各位的讨论感觉很有帮助。P2P现在的问题是如何商业化。文件共享在国外已经受到打压,此路不通。国内基于p2p的视频应用已经有一些(pplive,ppstream等),再去做此类应用似乎已经没有优势,至少比先行者拉下许多了。还有没有其他的路呢?很想和NeoRagex2002讨论一下。我的msn 是guy_distinguished@hotmail.com

 回复 引用   
#25楼[楼主2006-11-27 18:52 neoragex2002      
还有很多应用需要做的。比方说分布式哈希表方式构造的P2P洋蒜代理,这个是为了突破对单一代理服务器的封锁而提出的;再比方说P2P结构的浏览器、RSS Cache管理,这个是为了提高用户浏览器体验、克服带宽瓶颈而提出来的,等等。想法太多。
 回复 引用 查看   
洋葱代理是什么意思?P2P方式的代理可以理解为处理单点失败。P2P的浏览器只能自己玩玩,商业前景不明郎。毕竟,没有丰富的P2P内容,要一个浏览器有什么用。
看来你对技术的兴趣大过商业。再说说Kademlia,为了保证value的可获取性,存储value的node会重新publish这些value(key)。按照paper的说法,发布频率是每小时一次。paper的后面对这个算法有个优化,看了半天没看懂。大概是这样:
1 如果node 在t时刻收到store RPC,在下一个发布时间点(t+onehour,下一个小时),就不publish.这行么?考虑这样一种情形,
a) X 在t时刻publish (key,value)到 M,N,O上。
b) 在t + onehour时,M,N,O大致同时(因为这几个node存储value的时间稍有不同)重发布。
c)N首先完成lookup k nodes的任务,然后call Store RPC。
M收到N的Store RPC,于是决定在t + 2hour时不再发布。同理,N,O也会收到其他M的store RPC.这样在t+2hour时,M,N,O都不publish。这就破坏了每小时publish一次的模式,导致数据不能可靠的被获取。
Paper里面的优化似乎是想每小时只有一个节点publish。但他的算法按照我的分析却没有做到。


 回复 引用   
#27楼[楼主2006-11-28 14:10 neoragex2002      
不是P2P浏览器,是P2P的Cache管理。事在人为,现在都是技术发展领先商业的。你提到的优化我没有细看,Kademlia这一章节阐述得也不是很明白,不过我想其优化措施的出发点基本上都是启发式的,缺乏理论证明,大多以有限场合下的实验结果来说明问题,因此小瑕疵可以容忍,毕竟,在大网中进行时序角度的分布式协调大多得不偿失。
 回复 引用 查看   
#28楼 2006-12-26 13:52 Guo[未注册用户]
能不能再麻烦给详细介绍一下Kad从无到有的详细过程,发起节点与其它节点是否有区别,而且Kad的网络发起后是不可控的,能否加入可控的机制,等等,多谢!
 回复 引用   
neoragex2002您好!
我是菜鸟,有些问题不明白,想请教一下....KAD网络中HASH,ID是采用160位的,但为什么我看EMULE中KAD文件夹下的代码,觉得应该是128位的呢?还有EMULE中的KAD实现是不是不是传统的KAD实现啊,因为觉得EMULE中KAD的结点存储好象是采用树状结构的,根据hash找共同前缀而加如树中,并没有K-bucket的列表结构,而刷新,查找结点都跟您以上所述有点出入....请麻烦解释一下好吗
谢谢

 回复 引用   
#30楼[楼主2007-03-15 14:47 neoragex2002      
@ 无助女生
文章中的KAD是最早的实现,侧重于对基本概念的描述,并不是具体代码的实现,所以可能跟你所看的新版emule实现有所出入,因此仅供参考。

 回复 引用 查看   
neoragex2002您好!
恩,谢谢帮助

 回复 引用   
#32楼 2007-04-11 23:56 hl[未注册用户]
我感觉k桶应该改成只保存公网IP的结点,通过内网出来的就不保存了(保存了也访问不了),现在k桶的刷新机制似乎只要来一个包就会刷新k桶,这算是个缺陷吗?
 回复 引用   
#33楼[楼主2007-04-12 14:41 neoragex2002      
@hl
re: 我感觉k桶应该改成只保存公网IP的结点,通过内网出来的就不保存了(保存了也访问不了)
呵呵,这是ipv4 nat的缺陷,不是kademlia的缺陷;等ipv6普及后,便完全不会存在这种情况。

re: 现在k桶的刷新机制似乎只要来一个包就会刷新k桶
Least-recently Seen Eviction并不等于全部刷新吧,从设计上,其实只要是符合其节点快速更新、筛选要求的DS都是可以用的,当然,就实现而言,可优化的余地也很大。

 回复 引用 查看   
#34楼 2007-04-15 09:39 kidd[未注册用户]
请教一下。

当客户端第一次连接Kad网的时候,他是怎么找到一个kad网内的节点的?

文章说三:其一,不管通过何种途径,获知一个已经加入Kad网络的节点信息(我们可以称之为节点I),并将其加入自己的k-buckets

是否还是查询了中央服务器?还是说在某个端口使用了flood进行查找?

我就是对于开始不太理解。谢谢!

 回复 引用   
#35楼[楼主2007-04-15 17:54 neoragex2002      
@kidd
提供若干众所周知的bootrap节点。无需查询服务器或flooding。网络维护者只需保证至少一个bootrap节点在线即可。

 回复 引用 查看   
#36楼 2007-04-18 20:32 fengge[未注册用户]
请问bootrap节点是什么 我也有和kidd同样的疑问
 回复 引用   
#37楼[楼主2007-04-18 20:41 neoragex2002      
bootrap节点即“启动”节点,其特点如下:
1. 长时间在线,几乎是专门为其他节点提供首次入网服务
2. Node ID非常简单易记,且众所周知(160bit均为0,或者均为1,或者有规律的01相间)

 回复 引用 查看   
#38楼 2007-04-19 22:24 fengge[未注册用户]
k-桶保存了每一个节点的网络信息(Node ID,IP地址,UDP端口),但<key, value>是存放在那里的
 回复 引用   
#39楼[楼主2007-04-25 14:07 neoragex2002      
@fengge
<key,value>存放在Node ID==key的那个节点上,value的数据结构视存储何种数据而定。

 回复 引用 查看   
KAd网络是一个虚拟的网络吗?节点如何加入这个网络的?
 回复 引用   
#41楼 2007-11-05 20:42 蛙蛙池塘      
啊,你们这么早就讨论这个啦,强人呀
 回复 引用 查看   
#42楼[楼主2007-11-06 23:02 neoragex2002      
@ 蛙蛙池塘
hmm... 老话题了

 回复 引用 查看   
#43楼 2007-11-10 10:36 九片      
连1/3 都看不懂 -_-#,学习中...
 回复 引用 查看   
#44楼[楼主2007-11-11 07:11 neoragex2002      
@九片
呵呵,可以先找几篇概念性的文章看看,再回过头来看文章里面的细节,也许会容易理解一点。

 回复 引用 查看   
#45楼 2007-12-20 15:29 freddie[未注册用户]
汗啊~~

太谢谢楼主了,提供这么通俗易懂的文章。还有耐心回答每个人的问题。

 回复 引用   
#46楼 2008-01-02 16:01 p2p[未注册用户]
我对kad周期性发布本地的(key,value)不太明白

a) X 在t时刻publish (key,value)到 M,N,O上。
b) 在t + onehour时, 需要重新发布 (key,value)时,
是 X 再次发布还是 M,N,O 直接发布?

如果是 M,N,O 直接发布,会不会有一个问题?
如果 X 在t时刻发布了(key,value), 然后自己离网了, 会导致 (key,value) 中的 value 值无意义?

 回复 引用   
#47楼[楼主2008-01-02 20:23 neoragex2002      
@p2p
由X再次发布。X发布<key,value-X>还是要跟其他节点(如Y)发布<key,value-Y>在M/N/O上合并的,即所有相同key的value均合并成一个value向量。因此,如果X发布后离线,在有限的时间内,M/N/O上value向量中的value-X就是冗余的,它将随时间很快陈腐并被删除。

这些冗余信息是可以容忍的:比方说emule里面,你会发现有时kad一下子返回很长一串待连接的peer节点列表,但真正去连接这些节点的时候,你会发现这些节点其实已不在线。这就是你所说的情况。随着时间的推移,过时的不一致信息将因缺乏刷新而超时,最终在cache节点和目标节点上被删除。

 回复 引用 查看   
#48楼 2008-01-09 10:58 p2p[未注册用户]
谢谢 neoragex2002。 明白了。
 回复 引用   
#49楼 2008-03-09 21:26 dalu[未注册用户]
搂主,我想问那个“文件索引字典”存放在哪里? cache 里? 还有,如何收集当前所有拥有该文件的节点的网络信息?搂主可否再清楚讲一下原理。
 回复 引用   
#50楼[楼主2008-03-09 22:51 neoragex2002      
@dalu
"文件索引字典“的意思是:整个kad网路所起到的作用等同与一本"字典",而"字典"里面的”条目“则是分布式的存储在各个节点中。

 回复 引用 查看   
#51楼 2008-03-10 10:50 dalu[未注册用户]
谢谢搂主的及时回复,我还想问关于文件索引字典:
既然每个节点都存储了一个这样的条目<key ,value> ,那么这样的节点是如何收集拥有SHA1校验值下载文件所在的节点信息的?这样的条目信息是不是也存在于K-桶中?
你在论坛中还讲了一篇文章:BitTorrent中的数据块校验方式改进:Merkle Hashing Tree,不知道搂主实现了此算法没有?我查了下,好像没有太多论文讨论这个问题。
看来搂主对p2p还是相当了解,试问对等文件系统,你觉得哪个方面将会是研究的趋势和热点,或者需要再改进和完善的地方?能否具体谈谈。

 回复 引用   
#52楼[楼主2008-03-10 21:14 neoragex2002      
@dalu
假设某文件sha1为a,那么所有提供该文件下载的节点信息都会存放在id为a的节点n上,或被cache到离n较近的其他节点上。这不是由节点n来主动收集的,而是提供该文件下载的其他节点保存(或发布)到n上的。假设某节点m想获取该文件相关的节点信息,其必须对n发起查询,再从n或其邻近节点的回复中获得文件信息。

merkle哈希树思路很简单,但目前还没有实现到已有软件上。目前对等网络寻址路由方面的工作已经很多了,如果做学问的话,激励一致性分析与协作增强是近来p2p方面的一个新热点问题,通俗的说就是如何杜绝吸血,具体可参考这方面的pp,去年似乎jos上有一篇,infocom'07好像也有。我对p2p了解不多,以上只是一点愚见。

 回复 引用 查看   
#53楼 2008-03-11 09:48 dalu[未注册用户]
现在比较明了了。谢谢楼主!
 回复 引用   
#54楼 2008-03-14 10:32 jade[未注册用户]
请问节点(111)和(000)之间的距离是多少?节点(10)和节点(000)之间的距离又是多少呢?对于不在同一个层次的二叉树节点算距离是怎样计算的呢?
 回复 引用   
#55楼[楼主2008-03-15 07:25 neoragex2002      
@jade
直接XOR。本文没有涉及任何层次化的节点编址结构,所有节点ID均为160bits,并不存在诸如0000000001跟1的区别。

 回复 引用 查看   
#56楼 2008-04-07 09:32 jade[未注册用户]
谢谢楼主!
 回复 引用   
#57楼 2008-04-25 16:57 coolias[未注册用户]
楼主,我又来了,昨天真的不好意思,不过还差几个问题我还不清楚,还得请教你:
1:在emule中,peer与peer之间的数据传送可能走udp协议吗,如果可能,在什么情况下会产生这种传送方式呢?
2:在bitcommet中已经实现了内网互联的功能,就是通过udp打洞的方式在peer之间进行数据传送,那么除了这种情况下数据传送是走udp
协议, 在bt的目前实现中,还有其它的可能的情况吗?
3:目前的emule实现了内网互联的功能了吗?

再次麻烦,再次感谢!

 回复 引用   
#58楼[楼主2008-04-29 16:30 neoragex2002      
@coolias
一般内网互连用udp。kad查询一般也用udp。bc不公开源码,没关注过。官方emule内网互连功能虽有限,但已有增强客户端提供更好支持。内网互连网上介绍很多,可以自己看看。

 回复 引用 查看   
#59楼 2008-04-29 22:01 many[未注册用户]
你的意思是每个k桶里面只能放20个结点吗,那按照你那个图,是不是就是说1号k桶最多放1个节点,2号k桶最多放两个结点,也就是前面几个k桶不会放满20个节点?
 回复 引用   
#60楼 2008-05-24 19:29 hcj[未注册用户]
LZ你好,请问kademlia有没有涉及到NAT映射方面的问题呢?我在想,NODE与NODE如果都是内网用户的话,他们之间还是无法联系,也就无法查询,甚至目标节点(也是内网)跟下载节点之间根本无法联系,那这样还是得有个公网节点来完成打洞啊?这样质疑对吗?
 回复 引用   
#61楼[楼主2008-05-25 09:39 neoragex2002      
@hcj
nat映射跟kad并不存在本质联系,任何需要在nat背后提供服务的网络应用均要考虑nat映射的问题。另,nat内网互连存在多种类型,内网是否能互连、该以何种方式互连,本质上取决于用户所使用的nat具体设备类型;不是所有的互连方式均需要外部公网节点协助;打洞也不是内网互连的唯一途经,用户还可通过UPnP协议或手工对nat设备进行端口映射。

鉴于nat内网互连是个出土文物级的古老话题,且与kad没有必然联系,因此本帖对其不进行讨论,建议参考其他资料。

 回复 引用 查看   
#62楼 2008-05-27 12:59 nan[未注册用户]
楼主谈到 "利用Kad网络搜索并下载某一特定文件的过程为:通过关键词查询关键词字典,得到SHA1校验值,然后再通过该校验值查询Kad文件索引字典,从而获得所有提供该文件下载的网络节点,继而以分段下载方式去这些节点下载整个文件。"

我想提的问题是:

通过关键词所查询的关键词字典是本结点的吗?这个关键词字典是如何建立的?

谢谢!

 回复 引用   
#63楼[楼主2008-05-27 16:41 neoragex2002      
@nan
两本“字典”的含义请参考文中第2节。如何建立“字典”,请参考第5、8节。

 回复 引用 查看   
#64楼 2008-05-29 12:54 nan[未注册用户]
文章我又看了一遍,看能是因为我领悟力太差,还是不太明白。因此再麻烦你一下:

“当需要在Kad网络中存储一个条目时,可以首先通过节点查找算法找到距离 key最近的k个节点”
这一步是怎么查找的呢?K-桶中记录的是与本结点距离相关的结点信息,而不是与文件的ID相关的。

还有就是,结点加入时除了保存文件索引(在相应的结点填充文件索引字典),还要再填充关键词字典吗?根据一个文件名可以有很多关键词,那么要生成多少关键词条目啊?

谢谢你!

 回复 引用   
#65楼[楼主2008-06-01 10:53 neoragex2002      
@nan
某hash值为a的文件信息就存在某id值为a的节点上,所以查找节点就是查找文件信息。节点加入时,要重新发布自身所有共享的文件,以刷新kad网相关信息;由于kad网是有冗余的,慢慢发布就是了。

 回复 引用 查看   
几年前看到这篇文章不屑一顾,今天再次看到,突然觉得要是搭上这个做个音频播放器,岂不是太酷了,哇哈哈
 回复 引用   
#67楼 2008-06-11 16:06 nan[未注册用户]
谢谢博主您的耐心回答。

另有问题请教:
加入Kad网络中的各节点均保存有k-buckets,那么各结点之间的拓扑结构是怎样的呢?(比如说Chord算法中各结点首尾相连成一个Chord环)

再次感谢…

 回复 引用   
#68楼[楼主2008-06-11 21:36 neoragex2002      
@missdeer
老思路,对于mp3容易得很,只要查找速度足够快。

@nan
kad里面节点拓扑关系是松散的。除了节点ID、距离之外,其没有利用任何额外的拓扑属性,也没有任何拓扑假设。

 回复 引用 查看   
是啊,以前不懂这个,没想到那个上去,现在用DHT的东西越来越多了,真是个很有应用前景的技术啊
 回复 引用   
看了一眼emule的源代码,好像Kademlia有1.0和2.0,这两个有什么区别,能互通么
 回复 引用   
请问楼主,KAD还可以继续改进/优化吗?若可以,一般从哪里入手比较对头呢?能不能加上最近比较火的small world或者语义网的内容啊?
最近正在看这方面的paper,先谢谢楼主!

 回复 引用   
想起来,这协议要用在中文上进行搜索,光靠符号、标点之类的分隔还不够,还需要加入中文分词,昏。
另外,这些细节参数,比如k,应该是有一定规模节点数的前提吧。比如我在一个局域网内应用,最多用户数不会超过几百或几千,如果还是照搬这些参数取值,效果可能会很差吧。

 回复 引用   
#73楼[楼主2008-07-05 21:03 neoragex2002      
@missdeer
yes。至于参数动态调节,其实实现起来不麻烦。用适当统计方式可以做到,比方说bootrap节点统计,或者配合ed2k服务器统计,但同样,这也只是经验性质的调整,一般需要先做一下仿真。

@test2008
请参考第52楼。

 回复 引用 查看   
#74楼 2008-07-05 21:46 怪怪      
嗯嗯, 没想到你也研究这个,去年我也初步的涉及了一下KAD的算法, 不过后来就中断研究了。 今年8月开始我应该会投入主要精力在这方面, 到时候有没有兴趣一块探讨一下?
 回复 引用 查看   
#75楼[楼主2008-07-06 19:31 neoragex2002      
@怪怪
呵呵,好!欢迎交流!

 回复 引用 查看   
#76楼 2008-07-07 10:09 怪怪      
@neoragex2002
呵呵, 说是交流, 开始我肯定是吸血鬼的角色 :)

不过我一定保证尽快成长, 共同进步~

我把MSN短消息给你。

 回复 引用 查看   
#77楼 2008-07-10 09:25 ocenas[未注册用户]
@neoragex2002
麻烦楼主看一下我的理解可对,谢谢了。
当一个新的资源(如:warcraft_frozen_throne.iso)加入的时候,要做的事情是:
1.hash(warcraft_frozen_throne.iso)得到一个ID,并把它加入相应的文件索引字典。
2.hash(warcraft),hash(frozen),hash(throne),并把它们分别加入三个关键字字典。

 回复 引用   
#78楼 2008-07-10 09:32 ocenas[未注册用户]
还有为什么要做成两本字典。这样不就是要在这个KAD网络中作2次查询过程。
把这两个字典合成为一个不是可以节省查询时间吗?
如:
key file IP
warcraft warcraft_frozen_throne.iso 123.45.67.89
warcraft_frozen_throne.iso 210.25.21.2
warcraft12345.iso 20.13.25.2
678warcraft9.rar 150.24.012.07
frozen warcraft_frozen_throne.iso 123.45.67.89
warcraft_frozen_throne.iso 210.25.21.2

 回复 引用   
#79楼[楼主2008-07-10 20:23 neoragex2002      
@ocenas
感觉你对“什么是字典”的理解还不太对劲,不妨再深入了解下哈希表的概念,这两个问题自然也就明了了。

 回复 引用 查看   
最近刚刚接触bt,有几个问题让我很不解,特向楼主请教:
1,<key,value>对的存储是分布式的,原则上规定是把它存储在与节点id号最近的节点,另外在离节点最近的k个节点进行cache。我的问题是,这些cache之间有没有同步更新机制?因为我们知道,很多实现里面,get_peers得到value值后,就会立即返回,那么,如果我要向这个返回的节点publish,其余的cache怎么知道我的publish的动作呢?
2,如果我设法取得某一个特定节点的令牌,然后对其进行publish的动作,那么,会发生什么事情?因为这种行为是发生在协议规范之外,是否属于未定义?

希望您不吝赐教,谢谢!

 回复 引用   
#81楼[楼主2008-10-22 05:44 neoragex2002      
@ivgotcrazy
1. 暂无显式的同步更新机制。一般通过提高发布刷新频率和缩短条目超时来解决。
2. 我不太明白你的意思,我看不出这种操作有何特别之处?

 回复 引用 查看   
--引用--------------------------------------------------
neoragex2002: @ivgotcrazy

1. 暂无显式的同步更新机制。一般通过提高发布刷新频率和缩短条目超时来解决。

2. 我不太明白你的意思,我看不出这种操作有何特别之处?
--------------------------------------------------------
不好意思,可能我表述的不是太清楚。
1.我想问的是,网络上所cache的<key,value>条目是分布式的,假设他们一直在线,由于各个不同点cache节点接受的annouce可能并不一样,是不是意味着经过一段时间后,这些cache上的内容已经不相同了?另外,所谓的提高发布刷新率,是由谁来发布呢?是不是意味着只要我发布出去了,下载客户端就一定能得到我的信息?
2.我的意思是,因为正常情况下,我们要向一个cache announce,那么首先需要发送一个get_peers的消息,得到这个节点的一个令牌,然后通过这个令牌向这个cache节点进行发布。可是如果我已知某一个节点的ip,那么我可以自己向他发送一个get_peers的消息,然后得到他的一个令牌,接着向他进行announce,那么会发生什么情况?会在那个节点产生一个<key,value>并把我的信息加到里面去吗?

谢谢啦!

 回复 引用   
#83楼 2009-11-23 10:12 陈力      
我还没有明白你是怎么找到邻结点 ,假如文件a我已经获取到了这个目录,这时候我需要下载这个文件,这个文件的存储路径应该在互联网当中,这时候我需要获取到这个文件所存储的路径,这时候怎么去获取文件的存储路径 a: 路径存储在中心服务器当中,b :自己通过某种协议来寻找(不通过服务器) 如果方式为b这里应该要交待清楚,否则其它的一些实现应该不是很困难!
 回复 引用 查看