可能感兴趣的网络协议 -- P2P协议

时间:2024-04-01 15:55:39

作者:opLW
漫长寒假,结束了毕业论文的初稿。最近闲来无事学了点Flutter,感觉多个内容同时学可能会比较有趣,然后就重新捡起了网络协议看起了《趣谈网络协议》和《计算机网络》,进一步完善了对计算机网络整体结构的认知,然后随便记录下自己感兴趣的熟悉又陌生的协议。

目录

1. P2P简介
2. BT协议
3. 去中心化网络(DHT)

1. 简介

  • P2P全称Peer-to-Peer,是一种分布式网络。网络的参与者共享他们所拥有的一部分资源(处理能力、存储能力等),这些共享资源由网络提供服务和内容,能被其它对等节点(Peer)直接访问而无需经过中间实体。P2P打破了传统的Client/Server (C/S)模式,在网络中的每个结点的地位都是对等的。每个结点既充当服务器,为其他结点提供服务;同时也充当了客户端,享用其他结点提供的服务。因此当加入P2P网络中的节点越多时,可以提供服务的Peer就越多,那么对于每一个Peer可以使用的资源就越多,相应的就能越快的获取到资源。
  • P2P网络中,没有相对明确的中心节点,即“非中心化”。“非中心化”提高了整个网络的扩展能力、容错能力。同时大量的Peer引入了更多可供使用的资源。

2. BT协议

  • 2.1 BT简介 BitTorrent(“比特洪流”简称BT)是一个位于TCP/IP协议之上的P2P文件传输协议,属于应用层协议。BitTorrent是P2P协议的一种应用,除此之外还有KaZaA、eMute(电骡)等。
  • 2.2 BT种子 根据BitTorrent协议,文件发布者会根据要发布的文件生成提供一个torrent文件即.torrent文件,也称为"种子"。.torrent文件包含两部分的内容:
    • TrackerURL 在每一个BT网络中都有一个追踪器(Tracker),这个TrackerURL记录了追踪器的地址。追踪器负责管理洪流中的所有Peer,新的Peer加入网络时,都需要向追踪器登记并且要周期性的通知追踪器自己仍在网络中。
    • 文件信息
      • info区:这里指定的是该种子有几个文件、文件有多长、目录结构,以及目录和文件的名字。
      • Name字段:指定顶层目录名字。
      • 每个段的大小:BitTorrent(简称 BT)协议把一个文件分成很多个小段,然后分段下载。
      • 段哈希值:将整个种子中,每个段的 SHA-1 哈希值拼在一起。
  • BT网络的结构 这里借用《计算机网络》中的一张图。
    可能感兴趣的网络协议 -- P2P协议
    如图所示,各个Peer节点受追踪器的统一管理。这些Peer在网络中都是逻辑相邻的,即它们不一定在同一个局域网内,可能位于不同的局域网中(如图的下半部分所示)。
  • 2.3 获取资源的过程 下载时,BT 客户端首先解析.torrent 文件,得到 tracker 地址,然后连接 tracker 服务器。tracker 服务器回应下载者的请求,将其他下载者(包括发布者)的 IP 提供给下载者。下载者再连接其他下载者,根据.torrent 文件,两者分别对方告知自己已经有的块,然后交换对方没有的数据。此时不需要其他服务器参与,并分散了单个线路上的数据流量,因此减轻了服务器的负担。
    存在的问题 由于BT协议把一份文件分成很多段,所以向其他节点获取资源时,应该优先获取哪段?同一段资源可能存在于多个相邻节点中,那么应该向哪个节点获取呢?
    • 问题1 对于这个问题,使用最稀有的优先的原则。文件的一段资源可能存在于多个节点中,即存在多个副本,而对于副本相对较少的段,我们称为”稀有资源“。因此对于”稀有资源“,我们应该优先获取,避免拥有该资源的节点退出。
    • 问题2 在传输的过程中,节点会监测相邻节点的传输速度并从中选取速度较快的前四个节点(姑且称为”优先节点“),此后获取资源优先从这四个中获取,因为这些节点已经被”疏通“,网络较畅通。同时为了增加其他节点成为自己”优先节点“的可能性以及自己成为其他节点”优先节点“的可能性,每隔30秒,节点本身会随机的向其他相邻节点发送数据,以此来让速度更快的”优先节点“被发现。
  • 2.4 短板 这种方式特别依赖 tracker。tracker 需要收集下载者信息的服务器,并将此信息提供给其他下载者,使下载者们相互连接起来,传输数据。虽然下载的过程是非中心化的,但是加入这个 P2P 网络的时候,都需要借助 tracker 中心服务器,这个服务器是用来登记有哪些用户在请求哪些资源。所以,这种工作方式有一个弊端,一旦 tracker 服务器出现故障或者线路遭到屏蔽,BT 工具就无法正常工作了。因此就有了下面的”去中心化“。

3. 去中心化网络(DHT)

  • 3.1 DHT简介
    • DHT(Distributed Hash Table),称为”去中心化网络“。每个加入这个 DHT 网络的节点,都要负责存储这个网络里的资源信息和其他成员的联系信息,相当于所有人一起构成了一个庞大的分布式存储数据库,以此来削弱中心化带来的负面影响。为了维护这些信息,出现了许多算法如Chord、Pastry、CAN、Kademlia等,下面详细介绍Kademlia。
  • 3.2 Kademlia
    • 3.2.1 结构图 这里借用《趣谈网络协议》中的一张图。
      可能感兴趣的网络协议 -- P2P协议
      这种模式下的新变化:

      • 一个节点启动后都需要担任两个角色 一个是peer,监听一个 TCP 端口,负责管理文件的上传和下载;另外一个是DHT node,监听一个 UDP 的端口,负责管理节点之间的关系,同时DHT node有责任知道"相关文件"的存放位置,因此需要维护"相关文件"的索引信息。

        如何定义"相关文件" 每个文件可以计算出一个hash值,而DHT node有一个ID,该ID是和hash值相同长度的串。DHT算法是这样规定的:如果一个文件计算出一个hash值,则和这个hash值一样的DHT node,就有责任知道从哪里下载这个文件,即便它自己没保存这个文件,此时便称这个文件为这个节点的”相关文件“。

        采取”取近似值“的方式保证有多个节点知道某一文件的存放位置 一个文件当然不一定这么巧,总能找到和哈希值一模一样的,有可能一模一样的DHT node 也下线了,所以DHT 算法还规定:除了一模一样的那个 DHT node 应该知道,ID 和这个哈希值非常接近的 N 个 DHT node 也应该知道。什么叫和hash值接近呢?例如只修改了最后一位,就很接近;修改了倒数 2 位,也不远;修改了倒数3位,也可以接受。总之,凑齐了规定的数目即可。

      • .torrent文件不再存放TrackerURL而是List Node 为了削弱中心化的影响,将原本存放于追踪器中的节点信息进行备份,分散存放在各个DHT node中,所以.torrent中需要存放这些DHT node的地址信息,来让新加入的node可以顺利访问资源。

    • 3.2.2 获取资源的过程 主要分为以下几个步骤:

      • 新加入的node计算要下载文件段的hash值
      • 根据hash值在自己的List Node(List Node中的节点信息需要额外的维护)中查找相应的节点,如果查找到则直接访问该节点,查找不到则使用节点查找算法进行查找,最终一定能查找到与该文件相关的节点
      • 访问查找到的节点,获取资源
    • 3.2.3 List Node的维护 就像人一样,虽然我们常联系人的只有少数,但是朋友圈里肯定是远近都有。
      将DHT node进行分类 DHT 网络的朋友圈也是一样,远近都有,并且按距离分层,具体分法如下:

      1. 前面提到过每个DHT node都有一个ID,而这个ID为160位的串,下面为了简单起见仅使用5位
      2. 在 Kademlia 网络中,距离是通过异或(XOR)计算的。

      • 假设某个节点的 ID 为 01010,如果一个节点的 ID,前面所有位数都与它相同,只有最后 1 位不同。这样的节点只有 1 个,为 01011。与基础节点的异或值为 00001,即距离为 1;对于 01010 而言,这样的节点归为“k-bucket 1”。
      • 如果一个节点的 ID,前面所有位数都相同,从倒数第 2 位开始不同,这样的节点只有 2 个,即 01000和01001,与基础节点的异或值为 00010 和 00011,即距离范围为 2 和 3;对于 01010 而言,这样的节点归为“k-bucket 2”。
      • 如果一个节点的 ID,前面所有位数相同,从倒数第 i 位开始不同,这样的节点只有 2(i-1) 个,与基础节点的距离范围为 [2(i-1), 2i);对于 01010 而言,这样的节点归为“k-bucket i”。最终到从倒数 160 位就开始都不同。
      • 你会发现,差距越大,陌生人越多,但是朋友圈不能都放下,所以每一层都只放 K 个,这是参数可以配置。

      更新每一层的K个节点 前面讲到的是如何将DHT node进行分类,也知道了每一层只能放K个,由于节点可能会下线,所以需要及时的更新这些节点。下面看看如何更新:

      • 对于已存在于对应分层的节点,实行类似LRU(Last Recently Used)的算法,将使用到的节点置于顶层。
      • 对于不存在的则需要看分层是否已经满了。不满则直接存放,满了则PING 一下列表最上面,也即最旧的一个节点。如果 PING 通了,将旧节点挪到列表最底,并丢弃新节点保留旧节点;如果 PING 不通,删除旧节点,并将新节点加入列表。
    • 3.2.4 节点查找算法 Kademli通过折半查找的方式来收缩范围,对于总的节点数目为 N,最多只需要查询 log2(N) 次,就能够找到。具体例子如下:

      • 假设node A的ID为00110,要找nodeB的ID为 10000,异或距离为 10110,距离范围在 [24, 25),所以这个目标节点可能在“k-bucket 5”中,这就说明 B 的 ID 与 A 的 ID 从第 5 位开始不同,所以 B 可能在“k-bucket 5”中。
      • 然后,A 看看自己的 k-bucket 5 有没有 B。如果有,太好了,找到你了;如果没有,在 k-bucket 5 里随便找一个 C。因为是二进制,C、B 都和 A 的第 5 位不同,那么 C 的 ID 第 5 位肯定与 B 相同,即它与 B 的距离会小于 24,相当于比 A、B 之间的距离缩短了一半以上。
      • 再请求 C,在它自己的通讯录里,按同样的查找方式找一下 B。如果 C 知道 B,就告诉 A;如果 C 也不知道 B,那 C 按同样的搜索方法,可以在自己的通讯录里找到一个离 B 更近的 D 朋友(D、B 之间距离小于 23),把 D 推荐给 A,A 请求 D 进行下一步查找。例如,图中这个最差的情况。
        可能感兴趣的网络协议 -- P2P协议

      疑问 可能有疑问为什么这样就一定能找到和目标ID一摸一样的node啊?其实前面讲”相关文件“已经讲到并不一定存在和文件hash值一样的点,此时采取”取近似值“的方式找节点。因此这个不断缩小差异的过程不一定是为了找到一摸一样的节点,而是为了缩小差异来满足近似值要求,当达到取近似值要求时便可以结束。

最后感谢刘超老师的极客时间栏目《趣谈网络协议》和谢希仁老师的《计算机网络》,这两者对于学计算机网络都挺有帮助的。

万水千山总是情,麻烦手下别留情。
如若讲得有不妥,文末留言告知我,
如若觉得还可以,收藏点赞要一起。