zoukankan      html  css  js  c++  java
  • BT/DHT 相关

    摘录:https://zhuanlan.zhihu.com/p/34377702  

    https://github.com/shiyanhui/dht/wiki/

    http://www.aneasystone.com/archives/2015/05/how-does-magnet-link-work.html

    BT协议其实是一个协议簇,BEP-3 是其基本协议内容,其他的大部分都是围绕这个来进行扩展或补充。要想从BT网络中下载一个资源,必须具备以下部分:

    种子文件(也就是我们常说的种子,后缀是.torrent,本质上是一个由bencode编码的文本文件,其把资源分成很多虚拟块,并记录每个块的hash值,另外上面还记录着其他信息,比如文件大小、名字、Tracker服务器等)
    BT客户端(需要有专门解析BT协议的程序,这样才能下载,比如迅雷,电驴)
    Tracker服务器 (记录着peer和种子相关信息,起着中心调控的作用)
    下载资源的时候,客户端首先根据bencode(bencode是BT协议中的编码方式)解码种子文件,得到Tracker服务器的地址和资源信息,通过和Tracker服务器沟通得到其他已经下载该资源的peers信息(其他已经拥有该资源的客户端或者发布该资源的人),然后再和这些peers沟通得到自己想要的部分,即互通有无。由于把文件分成很多块来同时从不同的地方下载,这也就是为什么BT通常下载快的原因。

    BT协议簇中的DHT协议 是基于 Kademlia协议 建立的,其基本思想很好理解。DHT 由很多节点组成,每个节点保存一张表,表里边记录着自己的好友节点。当你向一个节点A查询另外一个节点B的信息的时候,A就会查询自己的好友表,如果里边包含B,那么A就返回B的信息,否则A就返回距离B距离最近的k个节点。然后你再向这k个节点再次查询B的信息,这样循环一直到查询到B的信息,查询到B的信息后你应该向之前所有查询过的节点发个通知,告诉他们,你有B的信息

    BT种子嗅探器就是利用了DHT协议得到peer信息后会向他之前查询过的节点发送通知这一点,这就是嗅探器的核心。

    剩下的工作就是我们要让更多的节点发给我们通知。那么如何让更多的节点发给我们通知呢?

    我们要不断的查询自己的好友节点表,并对返回回来的节点进行查询,这样才会有更多的人认识我们
    别人向我们查询Target的时候,我们要伪装成Target的好友,返回结果里边包括自己,这样会有更多被查询、收到通知的机会
    这就是BT种子嗅探器的原理,简单吧 :)

    种子下载器
    在BT网络中,通过上述原理收到信息并不是种子,而是发送消息者的ip和port、种子infohash(可以理解为种子的id)。我们如果想要得到种子的话,还需要做一番工作。这里涉及到另外一个非常重要的协议 BEP-09,BEP-09规定了如何通过种子infohash得到种子。
    首先同我们收到的消息里边的 ip:port 建立TCP连接,然后发送握手消息,并告知对方自己支持BEP-09协议,然后向对方请求种子的信息,收到对方返回的种子信息后,依次或同时请求每一个块。最有所有块收集完后,对其进行拼接并通过sha1算法计算其infohash,如果和我们请求的infohash值相同则保存起来,否则丢掉。

    磁力链接
    在网络中定位资源最简单的方法是URL(统一资源定位符),它是通过资源的位置来进行定位。而在DHT网络中,则是使用URN(统一资源名称)来进行定位,磁力链接就是基于文件内容的散列函数值来链接到特定文件,生成一个唯一的文件识别符,从而在DHT网络中定位并下载文件。 一个最简单的磁力链接格式如下:
    magnet:?xt=urn:btih:51df6808c739174c8f264701ba94460c5238d6ce
    其中urn为统一资源名称,btih是BitTorrent Info Hash的缩写,是BitTorrent使用的Hash函数。除了btih还可以是其他类型的Hash函数,但不如btih用的多。这一串长度为40的字符串正是文件内容的Hash,BT下载工具就根据这个Hash在DHT网络中定位下载文件。

    Torrent(种子)就保存了一个文件的一些信息,名字/长度/子文件目录/子文件长度等信息,其中最重要是拥有该文件的peers服务器,也因此,可以通过种子,向这些peers发送下载请求.下载到文件.
    但是在DHT(分布式哈希表)出现之前,所有节点都需要连接到Tracker服务器,以获取到拥有某个文件的peers(或者Torrent).
    DHT协议基于udp通讯,规定每个node(遵守BitTorrent协议,未实现提供下载功能的服务器)内部存储一个RoutingTable(路由表).该表存储了其他的node(或peer)节点.
    每个node的信息包括nodeId(随机的20个byte/ip/port(其中ip/port在udp通讯的包中都已经携带,所以,实际上最重要的就是nodeId)).
    而且定义了几种方法进行node间的交互(此处设A节点为请求方,B节点为响应方, 这些方法就是发送对应规则的请求响应报文,例如Http的GET/POST/DELETE等)

    ping: A向B发送请求,测试对方节点是否存活. 如果B存活,需要响应对应报文
    find_node: A向B查询某个nodeId. B需要从自己的路由表中找到对应的nodeId返回,或者返回离该nodeId最近的8个node信息. 然后A节点可以再向B节点继续发送find_node请求
    get_peers: A向B查询某个infoHash(可以理解为一个Torrent的id,也是由20个字节组成.该20个字节并非随机,是由Torrent文件中的metadata字段(该字段包含了文件的主要信息,也就是上文提到的名字/长度/子文件目录/子文件长度等信息,实际上一个磁力搜索网站提供的也就是这些信息).进行SH1编码生成的). 如果B拥有该infoHash的信息,则返回该infoHash的peers(也就是可以从这些peers处下载到该种子和文件). 如果没有,则返回离该infoHash最近的8个node信息. 然后 A节点可继续向这些node发送请求.
    announce_peer: A通知B(以及其他若干节点)自己拥有某个infoHash的资源(也就是A成为该infoHash的peer,可提供文件或种子的下载),并给B发送下载的端口.

    此外,node间的距离是通过nodeId进行异或计算的(也就是160个bit间进行异或)得出一个值,值越小,则距离越近. 由此可得出,越是高位的bit不相同(异或值为1),则值越大,距离越远(因为假设两个nodeId第1位就不同,其异或值必然大于2^160).

    DHT出现之后,假设一个新的节点想要加入该网络,只需要获取到已经在网络中的任何一个node信息,向其发送find_node请求即可.想要获取某个info_hash的peer,也可直接发送get_peers,而无需连接到Tracker服务器.

    github: 

    https://github.com/xiaojiong/DhtCrawler

    https://github.com/shiyanhui/dht

    https://github.com/BrightStarry/zx-bt

  • 相关阅读:
    几种垃圾回收算法
    Web前端研发工程师编程能力飞升之路
    Visual Studio使用小技巧6 – 为代码加上Using(Resolve using)和管理Using(Organize using) (转载)
    ASP.NET Session的七点认识
    经典SQL语句大全(转载)
    3种类型的程序员:“虫族”,“人族”,“神族”(转载)
    数据库设计中的14个技巧(转载)
    导致Asp.net站点重启的10个原因(转载)
    jQuery前端数据通用验证库,解放你的双手
    关于团队执行力的思考
  • 原文地址:https://www.cnblogs.com/sanmubai/p/10025043.html
Copyright © 2011-2022 走看看