前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Bittorrent 协议浅析(二)Tracker 和 对等节点

Bittorrent 协议浅析(二)Tracker 和 对等节点

原创
作者头像
青橙.
修改2023-09-27 12:09:52
6670
修改2023-09-27 12:09:52
举报
文章被收录于专栏:橙、橙、

0. 回顾

前序文章:

前文内容回顾:

  • BitTorrent 是一种用于分发文件的协议,它将需要分发的文件分片,然后在节点之间传递;
  • BitTorrent 使用元数据文件来描述需要分发的文件,元数据文件采用 bencode 编码;
  • 元数据文件(种子文件)的数据结构
  • 数据校验对分片进行 SHA-1 哈希计算比对;

1. Tracker

Tracker GET 请求

首先需要知道,Tracker 请求基于 HTTP 请求,通常使用 GET 方法,一个 Tracker GET 请求应该包含以下信息:

  1. info_hash(哈希): 元数据文件中 info 字段经过编码后计算 SHA-1 的哈希值,特别注意的是,用于计算该哈希值的内容应符合编码规范中所规定的排序规则和其他规则。
  2. peer_id(对等节点标识): 一个长度为20的字符串,标明下载器的ID,通常在创建新的下载任务时会根据一定规则生成。
  3. ip(IP 地址),可选: IP地址(或 DNS 名称),通常只有在 Tracker 和 下载器位于同一设备上标识需要才进行使用。
  4. port(端口号): 监听的端口号,在 BEP3 中给出如下通常描述: 下载器尝试监听端口6881,如果该端口已被占用,则尝试6882,然后6883,以此类推,直到6889,如果都占用则放弃。如今实际上的众多下载器都有各自的默认或会选择一个随机的端口号。
  5. uploaded(已上传量): 上传的总量,十进制ASCII编码。
  6. downloaded(已下载量): 下载的总量,十进制ASCII编码。
  7. left(剩余未下载量): 剩余需要下载的字节数,以十进制ASCII编码表示。 注意,这不能从已下载量和文件长度计算出来,因为可能是一个续传,而且有可能已下载的数据未能通过完整性检查,必须重新下载。
  8. event(事件),可选: 内容为 startedcompletedstopped,若为空则与未提供该键相同表示定期间隔内进行的通讯。started,表示下载刚开始;completed,表示下载已完成,如果在开始时文件已经完整,则不会发送completed,在停止时应发送stopped

一次 Tracker 请求的实质就是一个 HTTP GET 请求,以元数据文件部分示例的种子为例,在局域网内部署 tracker 服务器(过程略)进行请求示例。

首先计算信息部分哈希值,如下:

Info内容:

代码语言:json
复制
{
        "length": 1373744,
        "name": "ChromeSetup.exe",
        "piece length": 524288,
        "pieces": b"L\xb2k\xd9\x83\xa4\x84\x84\x00g\xeb\xf7\x1d\xfe3\xa2\xd9\x95\x0f\\\xa6\xb2E\xcd!^\xe3\xed\x8a\x85\xe7>(\x99\x9dU\x06g%b\x08@\xc9\x9fG\xb8S\x8f\x067K#3\xa7\xbf\xb8`N\xac3"
}

使用前文 encode_bencode 函数计算编码,并计算 SHA1 后对其进行 url 编码结果:

代码语言:txt
复制
%E7%D6%A1%A7%88-%E0%11%0E%3C%BB%FBP%91%FB%DE%EBg%1E%C1

根据 Tracker 请求结构,构建开始下载请求,如下:

  • info_hash=%e7%d6%a1%a7%88-%e0%11%0e%3c%bb%fbP%91%fb%de%ebg%1e%c1
  • peer_id=-None-ARandomString-,确保长度为20字符
  • ip=127.0.0.1
  • port=6881
  • uploaded=0
  • downloaded=0
  • left=1373744,尚未下载任何内容,left 剩余即为,文件大小
  • event=started,开始下载

最终构造的请求如下:

代码语言:text
复制
{TrackerURL}?info_hash=%f3%e4%3a%1c!)C%e2%18%eav%a0%1d%5d%c5%9b%d1%88%e6%a1&peer_id=-None-ARandomString-&port=6881&uploaded=0&downloaded=0&left=0&event=started

Tracker GET 响应

对上文其进行请求,得到 Tracker 返回如下:

Tracker返回内容
Tracker返回内容

进行解码,得到返回字典:

代码语言:json
复制
{
    "complete": 0,
    "downloaded": 0,
    "incomplete": 1,
    "interval": 1863,
    "mininterval": 931,
    "peers": b'\n\x00\xb29\x1a\xe1'
}

这是一个成功的请求格式,接下来来具体看看 Tracker 的响应内容。

果发生错误,则只需要有 failure reason 即可,无需其他内容。

如果是一个成功的响应,则响应内容应该包括:

  • interval(间隔):下载器在正常情况下应该在多久(秒)后进行下一次请求,整数
  • peers(对等方信息的列表):列表格式,每个信息都是一个字典,包含:
    • peer id(对等方ID),字符串
    • ip(IP地址或DNS名称),字符串
    • port(端口号),整数

根据上述内容容易发现,之前测试的 Tracker 返回信息 peers 并不是标准形式,这就要看 BEP0023 中所规定的紧凑方式返回 peers 列表,在紧凑方式下每个对等方信息由4字节的IPv4地址和2字节的端口号组成,不再包括Peers ID。

同时需要注意,由于紧凑方式被推荐使用,很多 Tracker 只支持这种方式返回,但作为下载器,必须同时支持。

对上述请求进行分析,可得:Tracker 希望 下一次请求在 1863 秒后,peers 列表:

代码语言:json
复制
[{'ip': '10.0.178.57', 'port': 6881}]

2. Peers 握手

BitTorrent的协议是对等的,没有服务器和客户端的概念,每一个节点(Peer)都是相同的,它们之间互相传输数据的形式也是一致的。

此处以TCP连接为例,节点之间首先建立 TCP 连接,随后开始握手,握手数据如下:

  • 1 字节 协议名称长度,固定为 19 (0x13);
  • 19 字节 协议名称,固定为 BitTorrent protocol; 注:此后所有整数均以四字节大端字序进行编码;
  • 握手后的前 8 字节为保留位,用于标记扩展协议,在未考虑扩展协议情况下,其值均为 0;
  • 信息哈希,如前文所述的 20 字节 SHA1 结算结果,通常,握手双方该部分内容应该一致,若需要进行多个下载,由响应方以同样的哈希进行响应;
  • Peer ID,如果 Tracker 使用标准格式传输节点列表,则需对 PeerID 进行验证,断开验证失败的连接;

双方一次发送上述数据,互相进行校验,即完成握手过程,长度为 0 的保持连接消息通常每 2 分钟发送一次,在请求数据传输期间,超时时间可以更短。

3. Peers 数据传输

推荐结合 Bittorrent 协议浅析(三)对等数据传输实例 共同完成此部分阅读。

在握手完毕后,双方便可以开始交换数据,所有非 保持连接(长度为 0)的数据均以单个字节开头,开头字节介绍:

标识

说明

0

choke

1

unchoke

2

interested

3

not interested

4

have

5

bitfield

6

request

7

piece

8

cancel

前四项,choke interested的含义如下:

  • 阻塞(Choked)或不阻塞(Unchoked):这表示一个对等方是否允许数据向对方传输。当一个Peer阻塞时,它不会发送数据给另一方,直到解除阻塞。
  • 感兴趣(Interested)或不感兴趣(Not Interested):这表示一个对等方是否希望对方传输数据。如果一个对等方对另一个对等方的数据感兴趣,那么它会请求数据块。

当连接建立后,默认状态为阻塞和不感兴趣。

  • have:当下载器完成一块数据的下载并校验哈希之后,通过 have 通知其他节点。have 内容包括分片的整数的索引。
  • 比特表(bitfield):bitfield 只在建立连接后一次发送,它通过比特表的形式告知其他节点已经拥有的数据分片,需要注意的是,如果发送方在连接建立时未拥有任何数据块,它可以选择跳过发送 'bitfield' 消息,bitfield 并不是必须的。
  • 请求(request)和提供(piece):一个节点可以通过 request 向其他节点请求,或者通过 piece 来为其他节点提供数据,请求包括整数的分片索引、起始数据偏移量和分片大小,也可以视为请求数据的大小,提供包括数据长度,开始标记(7)和数据内容。
  • 取消(cancel):cancel 与 request 消息的负载相同,下载器为高效下载,可同时向多个节点请求同一个分片,当获取到一个分片并校验后,通过 cancel 告知其他节点停止发送。

Tracker 和对顶节点部分 完

第二部分 Tracker 和对等节点 暂时就到这里,实践和拓展协议等先关内容的分析之后链接会放在这里:

最后,征文活动广告:

我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0. 回顾
  • 1. Tracker
    • Tracker GET 请求
      • Tracker GET 响应
      • 2. Peers 握手
      • 3. Peers 数据传输
      • Tracker 和对顶节点部分 完
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
      http://www.vxiaotou.com