什么是BitTorrent v2?现在就带你一探究竟

BitTorrent-v2 是一项旨在从哈希函数算法 SHA-1  改进的努力,鉴于新的哈希函数不会向后兼容,因此还提出了一些其他更改,而我们无论如何都会受到兼容性的影响。这篇文章描述了 BitTorrent v2 协议的新功能。

SHA-256

BitTorrent v2 的哈希函数数据值已更改为 SHA-256。这样做的一个结果是哈希是 32 字节而不是 20 字节。在 BitTorrent v2 中,文件信息也由 SHA-256 计算,这带来了与 DHT 和 Tracker 的兼容性挑战,DHT 和 Tracker 的协议需要 20 字节的哈希。为了解决这个问题,DHT 和 Tracker  通知和查找 v2 种子使用截断为 20 字节的 SHA-256 信息哈希。

这是创建 v2 协议的初衷之一。这意味着从根本上说,v2 种子将由与 v1 种子不同的哈希来标识,即使共享相同的文件,v1 种子也会创建一个单独的节点群组。

Работа с SHA-256

哈希树

在 BitTorrent 中,将一个文件划分成多个固定大小的块,并对每个块进行哈希计算得到的哈希值。这些哈希值被用来验证下载的文件块是否正确,以确保下载的文件的完整性和一致性。

当一个文件被划分成多个块时,BitTorrent 会计算每个块的 SHA-1 哈希值,并将结果存储在种子文件(.torrent 文件)中。在下载过程中,下载器会接收到所有块的哈希值,并且在下载每个块时都会重新计算哈希值以验证其完整性。如果下载的块的哈希值与种子文件中的哈希值不匹配,则该块被视为损坏或无效,并被丢弃并重新请求下载。

此方法的使用可以有效减少数据损坏和下载错误的可能性,并确保下载的文件的完整性和一致性。

在 BitTorrent v1 中,哈希值包含在 .torrent/metadata 中(在元数据文件中)。在大多数情况下,哈希值是种子文件(.torrent 文件)大小的主体。为了将种子文件(.torrent 文件)大小保持在大文件的范围内,可以增加哈希块的大小,这意味着每个哈希表示文件的较大部分。采用大片段表示的后果是,如果哈希验证失败,则必须重新下载文件的较大部分,直到该哈希块通过哈希验证。

大文件

在 BitTorrent 中,大文件指的是大于 2GB 的文件。因为 BitTorrent 在文件下载时将其分成许多小文件块下载,而每个块的大小默认为 256KB。但是,对于超过 2GB 的文件,如果按照默认块大小进行切分,会导致块的数量过多,从而影响下载速度和效率。因此,在处理大文件时,BitTorrent 会根据文件大小动态地调整块的大小,以保证下载速度和效率的平衡。
hash tree

改进这两个指标的一个旧想法是使用默克尔树来表示哈希块。这让种子文件(.torrent 文件)可以很小,因为您只需要哈希树的根哈希。BitTorrent v2 使用默克尔树表示哈希块具有以下优点:

  • 种子元数据(特别是 .torrent文件 的元数据部分)变得小得多。这减少了添加磁力链接时的启动延迟,因为在种子本身开始下载之前需要下载的字节更少。
  • 下载的数据可以在单个数据块级别进行验证。这意味着如果对等方发送损坏的数据,可以立即发现,只需要重新下载 16 kiB。发送损坏数据的对方也即可以确定。这是对在 v1 中识别不良对方(有时称为智能禁令)所需的启发式方法的极大改进。

哈希树的叶子节点始终为 16 kiB,无论块大小如何。与其说哈希块实际上是片段内容的哈希值,它是哈希树块的根。即完整默克尔树的子树。

在 v2 中,种子文件(.torrent 文件)仍必须包含这些哈希块(实际上是默克尔树中表示哈希块级别的哈希)。这有助于分发和存储哈希,以便在重新启动正在做种的客户端时不必重新计算它们。它们也存储在恢复状态中。对于 v2 种子来说,种子文件(.torrent 文件)并不小,因为它仍然包含哈希块,但元数据是,这是磁力链接开始下载所需的部分。

Example tree

具有 4 个块且片段大小为 32 kiB(每段 2 个块)的文件的示例树

每个文件中的哈希树

BitTorrent v2 不仅使用哈希树,而且还为种子文件中的每个文件形成一个哈希树。这有几个优点:

  • 相同的文件将始终具有相同的哈希值,并且可以更轻松地从一个种子移动到另一个种子(创建种子时),而无需对任何内容重新计算哈希值。相同的文件也可以更容易地在不同的节点群组中识别,因为它们的根哈希仅取决于文件的内容。
  • 所有文件的数据块都将被同样对齐,这意味着每个文件之后都有隐式填充文件

隐式填充文件

隐式填充文件是指在下载过程中自动生成的空文件,它们的作用是为了填充下载目录中的空间,便更好地组织下载的文件。这些空文件的大小通常是固定的,通常为 0 字节或一些小的固定大小,例如 512 字节或 1MB。这些文件通常被称为“隐式填充文件”,因为它们是由 BitTorrent 客户端自动创建的,而不是由种子文件中明确指定的。这些文件的存在可以帮助确保下载的文件在磁盘上的布局与原始文件相同,从而使得文件的组织更加清晰,方便管理。

这解决了长期以来的愿望,即更轻松地识别重复文件,或跨节点群组查找文件的多个来源。

目录结构

如前所述,大多数时候,哈希块占据了元数据中的大部分空间。例外的是含有大量小文件的种子;然后是占用最多空间的文件列表。在 v1 种子中,文件列表表示为具有完整路径的单个文件列表。在具有深层目录结构(或只是具有长名称的目录)的种子中,这些目录名称将被多次重复,从而加剧问题。

v2 种子通过对目录结构使用更有效的编码来解决此问题,并且重复更少。目录结构不是平面列表,而是存储为树(使用Bencode 的字典)。这会导致目录名称只被提及一次。例如:

'files': [
    { 'attr': 'x', 'length': 12323346, 'path': [ 'F' ] },
    { 'attr': 'p', 'length': 62958, 'path': [ '.pad', '62958' ] },
    { 'attr': 'x', 'length': 2567, 'path': [ 'this is a very long directory name that ends up being duplicated a lot of times in v1 torrents', 'A' ] },
    { 'attr': 'p', 'length': 62969, 'path': [ '.pad', '62969' ] },
    { 'attr': 'x', 'length': 14515845, 'path': [ 'this is a very long directory name that ends up being duplicated a lot of times in v1 torrents', 'B' ] },
    { 'attr': 'p', 'length': 33147, 'path': [ '.pad', '33147' ] },
    { 'attr': 'x', 'length': 912052, 'path': [ 'this is a very long directory name that ends up being duplicated a lot of times in v1 torrents', 'C' ] },
    { 'attr': 'p', 'length': 5452, 'path': [ '.pad', '5452' ] },
    { 'attr': 'x', 'length': 1330332, 'path': [ 'this is a very long directory name that ends up being duplicated a lot of times in v1 torrents', 'D' ] },
    { 'attr': 'p', 'length': 45924, 'path': [ '.pad', '45924' ] },
    { 'attr': 'x', 'length': 2529209, 'path': [ 'this is a very long directory name that ends up being duplicated a lot of times in v1 torrents', 'E' ] }
    ],

与 v2 文件树相比(这也包括默克尔树根哈希):

'file tree': {
    'F': { '': { 'attr': 'x', 'length': 12323346, 'pieces root': 'd1dca3b4a65568b6d62ef2f62d21fcdb676099797c8aa3e092aa0adcb9a9f6a5' } },
    'this is a very long directory name that ends up being duplicated a lot of times in v1 torrents': {
      'A': { '': { 'attr': 'x', 'length': 2567, 'pieces root': 'f6e5b48ebc00d7c6351aafdec9a0fa40ab9c8effe8ac6cfb565df070d9532f70' } },
      'B': { '': { 'attr': 'x', 'length': 14515845, 'pieces root': '271d61e521401cfb332110aa472dae5f0d49209036eb394e5cf8a108f2d3fb03' } },
      'C': { '': { 'attr': 'x', 'length': 912052, 'pieces root': 'd66919d15e1d90ead86302c9a1ee9ef73b446be261d65b8d8d78c589ae04cdc0' } },
      'D': { '': { 'attr': 'x', 'length': 1330332, 'pieces root': '202e6b10310d5aae83261d8ee4459939715186cd9f43336f37ca5571ab4b9628' } },
      'E': { '': { 'attr': 'x', 'length': 2529209, 'pieces root': '9cc7c9c9319a80c807eeefb885dff5f49fe7bf5fba6a6fc3ffee5d5898eb5fdb' } }
      }
    },

区块大小

在 v1 种子中,一个哈希块的大小不受规范的限制。拥有小于 16 kiB 的哈希块没有多大意义,但也是允许的。创建的绝大多数种子都使用两段大小的幂,但有一些异常值不是,但仍能被 16 kiB 整除。v2 种子通过要求固定尺寸来收紧要求:

  • 2的幂

2的幂

指在二进制表示中只有一个非零位(通常是最高位)的正整数。这意味着它可以被写成2的某个非负整数次幂的形式。例如,2、4、8、16等都是2的幂,因为它们可以分别写成2^1、2^2、2^3、2^4等形式。
由于计算机中使用的是二进制系统,因此2的幂常常用于计算机科学中的数字表示和运算。例如,在内存或硬盘驱动器的分配中,通常会使用2的幂作为块大小,以便能够更有效地利用可用空间。另外,许多算法和数据结构也要求数组的大小必须是2的幂,以便进行更快速的计算和访问。
  • 大于或等于 16 kiB

这样做的主要原因是哈希块适合哈希树。由于 v2 哈希块实际上是该片段的默克尔哈希树根,因此它必须表示两个区块的幂。

编码

种子文件(.torrent 文件)是用 Bencode 编码的树结构。在 Bencode 编码中,单一赋值有多个可能性编码的情况偶有出现。整数可以用前导零编码,也可以不使用;0 可以编码为负 0。这些编码一直是非法的,但解析器历来很宽容并接受它们。也许最常见的例子是如何要求字典中的键按字典顺序排序。但是,一些种子创建者未能对它们进行排序,因此客户端接受了它们。

这主要导致在 Bencode 编码结构往复转换时出现问题。解析后,字典条目的特定顺序或前导零的特定数量可能会丢失。因此,在重新编码结构时,可能会有所不同。如果被往复转换的元数据,则哈希信息已被更改,编码会中断。

libtorrent 现在通过拒绝加载任何包含以下内容的 v2 种子文件来执行这些限制:

  • 具有任何前导零的整数(0 本身除外)。例如:“i0004e
  • a 0 编码为 -0。即:“i-0e
  • 条目未正确排序的字典。例如:“d1:B3:foo1:A3:bare”(“A”应该在“B”之前排序)

强制执行这些编码还有助于使两个人更有可能从相同的文件创建种子,最终产生相同的哈希信息和相同的种子。

磁力链接

磁力链接协议已扩展为 v2 种子。比如 v1 SHA-1 哈希信息的前缀 urn:btih: 一样,有一个新的用于完整的 v2 SHA0256 哈希信息前缀 urn:btmh:

例如,磁力链接如下所示:

magnet:?xt=urn:btmh:<tagged-info-hash>&dn=<name>&tr=<tracker-url>

带有 btmh 前缀的哈希信息是以十六进制编码的多重哈希格式的 v2 哈希信息。实际上,这意味着它将具有 0x12 0x20 的双字节前缀。可以在磁力链接中包含 v1 (btih) v2 (btmh) 哈希信息,以实现向后兼容性。

向后兼容性

BitTorrent v2 中所有不向后兼容的新功能都经过精心赋予了新名称,以允许它们与 v1 对应项共存。因此,可以创建混合种子。也就是说,可以同时参与 v1 和 v2 节点群组的种子,提供相同的文件。

混合种子有两个哈希信息,一个 v1 SHA-1 哈希,一个(可能截断)SHA-256 哈希。这形成了两个节点群组,或一个隔离的节点群组。libtorrent 将同行标记为是否支持 v2。此信息也通过新的对等交换 (PEX) 标志进行中继。

PEX

BitTorrent 中的 PEX 是一种用于对等交换(peer exchange)的协议扩展。当客户端通过 Tracker 获取到一组初始的 peer 列表后,它可以使用 PEX 来获取更多的 peer。
PEX 使得客户端之间能够交换已知的 peer 列表,而无需依赖 Tracker。这种交换通常发生在两台客户机建立直接连接时,并且可以帮助改善下载速度和提高网络效率。
PEX协议的工作原理如下:当一个客户端与一个 peer 连接后,它会请求那个 peer 的可用peer 列表,并将其与自己的 peer 列表进行比较。如果存在新的 peer,客户端就会向那个 peer 发送一个 PEX 消息,告诉它有哪些其他 peer 可供连接。被请求的 peer 也会做出类似的响应,从而使得整个网络中的 peer 列表逐渐扩大。

混合种子文件(.torrent 文件)包括哈希块以及每个文件的根哈希。

参考链接

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注