BitTorrent 的工作原理?简单易懂的指南
目录
💭 谁创建了 BitTorrent?
📑 高层概述
🧀 BitTorrent 的片段选择算法
🌱 使用“以牙还牙”策略进行资源分配
😎 乐观畅通
🤕 反冷落
🐝 什么是追踪器?
🐍 分布式哈希表
📌 路由表
🤺 对 BitTorrent 的攻击
👋🏻 结论
不谈用 BitTorrent 下载东西,也不谈最好的客户端。
只是深入研究它的技术方面。
任何人都可以阅读这篇文章。无需任何网络或 BitTorrent 知识即可阅读。
BitTorrent 是传输大文件最常用的协议之一。2013 年 2 月,BitTorrent 占据了全球总带宽的 3.35%,超过了文件共享专用带宽(6%)的一半。
让我们开始吧。
目录
- 💭 谁创建了 BitTorrent?
- 🥊 BitTorrent 与客户端服务器下载
- 📑 高层概述
- 📁 Torrent 描述符文件中到底有什么?
- 🧀 BitTorrent 的片段选择算法
- 🌆 什么是子碎片和碎片选择算法?
- 🌱 使用“以牙还牙”策略进行资源分配
- 🎐 阻塞算法
- 😎 乐观畅通
- 🤕 反冷落
- 🤔 如果我们仅上传怎么办?
- 🐝 什么是追踪器?
- 🧲 磁力链接 - 无追踪器种子
- 🐍 分布式哈希表
- 📌 路由表
- 🤺 对 BitTorrent 的攻击
💭 谁创建了 BitTorrent?
布拉姆·科恩 (Bram Cohen)于 2001 年发明了 BitTorrent 协议。科恩用 Python 编写了第一个客户端实现。
2002 年夏天,科恩收集了免费色情内容来吸引测试人员使用 BitTorrent。
🥊 BitTorrent 与客户端服务器下载
传统的下载是服务器上传文件,客户端下载文件。
对于流行文件来说,这不是很有效。
500 人同时下载同一个文件,服务器就会不堪重负。这种压力会限制上传速度,导致客户端无法快速下载文件。
其次,客户端-服务器架构的成本很高。文件的受欢迎程度越高,我们支付的费用也就越高。
第三,它是中心化的。假设系统崩溃了,文件就不存在了——没人能下载它。
BitTorrent 旨在解决这些问题。
在对等网络中,每个对等点都与网络中的每个其他对等点相连接。
半集中式对等网络拥有一个或多个比大多数对等点具有更高权限的对等点。
📑 高层概述
BitTorrent 是一种文件共享方式,通常用于传输大型文件。BitTorrent 是单一文件共享源(例如服务器)的替代方案。BitTorrent 可以在较低带宽下高效运行。
BitTorrent 客户端的第一个版本没有搜索引擎,也没有对等交换,想要上传文件的用户必须创建一个小型的torrent 描述符文件,然后将其上传到 torrent 索引站点。
当用户想要共享文件时,他们会为文件做种。这个用户被称为做种者。他们会将一个种子描述符文件上传到交换器(我们稍后会讨论这一点)。任何想要下载该文件的人都会下载这个种子描述符。
我们将下载种子的用户称为peers。他们的种子客户端会连接到一个 Tracker(稍后讨论),Tracker 会向他们发送一个 swarm 中其他种子和 peers 的 IP 地址列表。swarm指的是所有与某个种子相关的 PC。
torrent 描述符文件包含我们正在下载的文件的跟踪器和元数据列表。
对等方将连接到种子并下载文件的各个部分。
一旦同伴完成下载,他们就可以充当种子。不过,在下载的同时充当种子也是可行的(而且很常见)。
一旦种子将文件共享给其他用户,该用户将充当种子。BitTorrent 不同于客户端-服务器模型(只有一个服务器上传文件),允许多个用户上传同一个文件。
BitTorrent 将文件分割成若干个块,每个块的大小都固定。有时是 256KB,有时是 1MB。每个对等体收到一个片段后,就成为其他对等体该片段的种子。
使用 BitTorrent,我们不再拥有单一的下载来源。我们可能会从你的国家下载一些内容,然后再从遥远的国家下载一些你国家没有的内容。
该协议会对各个片段进行哈希处理,以确保没有种子篡改原始文件。然后将哈希值存储在跟踪器的 torrent 描述符中。
BitTorrent 的工作原理大致如下。现在我们将进行详细介绍。我们的目标是回答以下问题:
- 如果对方只下载而不上传会怎么样?
- 我们从谁那里下载,或者上传给谁?
- 什么是磁力链接?
- 什么是 torrent 描述符?
- 使用什么哈希算法?
- BitTorrent 如何选择要下载的部分?
还有更多。
📁 Torrent 描述符文件中到底有什么?
它是一个字典(或哈希图)文件。
该文件描述如下:
- 宣布
跟踪器的 URL。还记得之前我们联系跟踪器服务器查找使用相同文件的其他用户吗?我们通过使用种子描述文件中的“announce key”找到了跟踪器。
- 信息
这映射到一个字典,其键取决于是否共享一个或多个文件。键如下:
文件(信息的子项,是一个列表)
Files 仅在共享多个文件时存在。Files 是一个字典列表。每个字典对应一个文件。
每个字典都有 2 个键。
长度——文件的大小(以字节为单位)。
路径- 与子目录名称对应的字符串列表,其中最后一个是实际文件名。
- 长度
文件的大小(以字节为单位)(仅当共享一个文件时)
- 姓名
建议的文件名。或者建议的目录名。
- 件长
每片的字节数。
片段的长度必须是 2 的幂,且至少为 16KiB。
这是 $$2 8 \; KiB = 256 \; KiB = 262,144 \; B$$
- 件
一个哈希列表。
基于不同数据块计算的哈希值列表。我们将数据拆分成多个部分。计算这些部分的哈希值,并将它们存储在一个列表中。
BitTorrent 使用 SHA-1 算法,返回 160 位哈希值。分片将是一个长度为 20 字节倍数的字符串。
如果 torrent 包含多个文件,则按照文件在文件目录中出现的顺序连接这些文件来形成片段。
种子中所有片段的长度都是完整的,除了最后一段可能较短。
现在,我可以猜出你在想什么了。
“SHA-1?这是什么?21世纪初?”
我同意。BitTorrent正在从 SHA-1 迁移到 SHA256。
还是一头雾水?别担心!我设计了这个 JSON 文件,用来描述种子文件的样子。注意:我把一些内容连接起来了,这样更容易阅读和理解整体布局。这些数字是我根据 BitTorrent 种子描述符的规则编排的。
{
"Announce": "url of tracker",
"Info": {
"Files": [
{
"Length": 16,
"path": "/folder/to/path"
},
{
"length": 193,
"path": "/another/folder"
}
]
},
"length": 192,
"name":" Ubuntu.iso",
"Pieces length": 262144,
"Pieces": [AAF4C61DDCC5E8A2DABEDE0F3B482CD9AEA9434D, CFEA2496442C091FDDD1BA215D62A69EC34E94D0]
}
🧀 BitTorrent 的片段选择算法
BitTorrent 中最大的问题之一是“我应该选择下载哪些部分?”
在传统的客户端-服务器模型中,我们会下载整个文件。但现在,我们可以选择下载哪些部分。
我们的想法是下载那些别人没有的碎片——那些稀有的碎片。通过下载这些稀有的碎片,我们通过上传它们来让它们变得不那么稀有。
🌆 什么是子碎片和碎片选择算法?
BitTorrent 使用 TCP(一种数据包传输协议)。TCP 有一种称为慢启动的机制。
慢启动是一种平衡 TCP 网络连接速度的机制。它会逐渐增加传输的数据量,直到达到网络的最大承载能力。“慢启动”cwdn
代表拥塞窗口。
TCP 这样做是因为如果我们一次发送 16 个连接,服务器可能无法适应流量,并且网络将会发生拥塞。
如果我们不定期发送数据,TCP 可能会以比正常速度更慢的速度限制我们的网络连接。
BitTorrent 通过将数据片段分解为进一步的子片段来确保始终发送数据。
每个子片段大小约为 16KB。片段的大小不固定,大约为 1MB。
协议始终会将一定数量的请求(例如五个)以管道方式传输子片段。当新的子片段下载完成后,客户端会发送新的请求。这有助于加快速度。
可以从其他对等点下载子片段。
两个核心策略控制着棋子选择算法。
1️⃣ 严格的政策
一旦 BitTorrent 客户端请求某个片段的子片段,则会先请求该片段的剩余子片段,然后再请求其他片段的子片段。
在此图中,首先下载该片段的所有子片段比开始下载另一个片段更有意义。
2️⃣ 最稀有的
BitTorrent 的主要策略是优先选择最稀缺的。我们希望下载其他用户数量最少的那个文件。
这样我们就可以让它变得“不稀缺”。如果只有一个节点拥有某个片段,而该节点离线了,那么就没有人能获得完整的文件了。
这项政策有很多好处。
培育种子
Rarest 首先确保我们只从种子中下载新的片段。
种子将作为瓶颈开始。与文件对等的一个。
下载者可以看到他们的同伴拥有哪些片段,最稀有优先策略将导致我们从种子中获取尚未被其他同伴上传的片段。
让我们想象一下。
节点(对等体)列表是相互连接的。我无法画出这个,因为图表不太理想。
每个箭头指向该对等体已下载的子片段。我们下载了一个除了种子之外没有其他人拥有的子片段。这意味着这个子片段很稀有。
我们的上传速率高于种子,所以所有同伴都会想从我们这里下载。而且,他们会想优先下载最稀有的片段,因为我们是这两个最稀有片段的持有者之一。
当每个人都从我们这里下载时,我们可以更快地从他们那里下载。这就是针锋相对算法(稍后讨论)。
提高下载速度
持有该片段的对等体越多,下载速度就越快。这是因为我们可以从其他对等体下载子片段。
启用上传
稀有作品最受其他玩家的青睐,而获得稀有作品意味着其他玩家会有兴趣从我们这里上传。正如我们稍后会看到的,我们上传的越多,下载的也就越多。
最常见的最后
将最常见的片段放在下载的最后是明智的。由于许多同伴都持有常见的片段,因此下载这些片段的概率比下载稀有片段的概率要大得多。
防止最稀有的物品丢失
当种子死亡时,文件的所有不同部分应该分布在剩余的对等体中的某个地方。
3️⃣ 随机第一件
一旦下载完毕,就没什么可上传的了。我们需要快速获取第一个片段。最稀缺的优先策略是慢速。稀缺片段的下载速度较慢,因为我们只能从少数几个节点下载它的子片段。
4️⃣ 终局模式
有时,传输速率较慢的对等体会尝试给我们一个子片段,从而导致下载延迟。为了避免这种情况,我们提供了“终局模式”。
还记得管道原则吗?总有多个子片段请求处于待处理状态。
当对等节点请求到所有缺少的子块时,它们会将此请求广播给所有对等节点。这有助于我们获取文件的最后一个块。
如果对等方有缺失的子片段,他们会将其发送回我们的计算机。
一旦子片段到达,我们就会发送一条取消消息,告诉其他对等方忽略我们的请求。
🌱 使用“以牙还牙”策略进行资源分配
BitTorrent 中不存在集中式资源分配。相反,每个用户都会最大化自己的下载速率。
同伴会从任何他们能下载的人那里下载。为了决定上传给谁,他们会使用“针锋相对”算法的变体。
针锋相对策略源自博弈论,其精髓在于:
“己所不欲,勿施于人”
- 第一步,合作
- 在每个后续步骤中,重复对手在前一步所做的
- 做好在实施一次报复行为后原谅的准备
🎐 阻塞算法
阻塞是指暂时拒绝向另一个对等体上传,但我们仍然可以从他们那里下载。
为了合作,同伴们会上传;为了不合作,他们会“扼杀”与同伴的连接。其原则是,向已经向我们上传过数据的同伴们上传数据。
我们希望同时建立多个双向连接并实现帕累托效率。
如果不存在其他分配方式使得某个人的境况变得更好,而没有某个人的境况变得更糟,那么我们认为这种分配方式是帕累托有效的。
因此,最大的问题是如何确定哪些对等体需要被扼杀以及哪些对等体需要被解除扼杀?
一个对等体始终会解除其固定数量的对等体阻塞(默认值为 4)。
当前下载速率决定哪些对等体需要解除阻塞。我们使用 20 秒的平均值来决定。由于使用 TCP(慢启动),快速阻塞和解除阻塞是不理想的。因此,每 10 秒计算一次。
如果我们的上传速率高,就会有更多用户允许我们从他们那里下载。这意味着,如果我们上传速度快,就能获得更高的下载速率。这是 BitTorrent 协议最重要的特性。
该协议禁止许多“搭便车者”,即只下载而不上传的同行。
为了使对等网络高效运行,所有对等方都需要为网络做出贡献。
😎 乐观畅通
BitTorrent 还允许额外的不受阻碍的对等体,其中不使用下载速率标准。
我们称之为乐观畅通。检查未使用的连接并不比检查正在使用的连接更好。
我们每 30 秒切换一次乐观畅通连接。这足以让上传速度达到最高。上传速度也一样。如果新的连接比现有的某个畅通连接更好,它就会取代它。
乐观的解开是随机选择的。
这也使得那些只下载而不上传的同伴即使拒绝合作也能下载文件,尽管他们的下载速度会慢得多。
🤕 反冷落
如果所有上传到其他节点的节点都决定阻塞连接,会发生什么情况?这时,我们就必须寻找新的节点,但乐观解除阻塞机制每 30 秒只会检查一个未使用的连接。为了帮助下载速度更快恢复,BitTorrent 提供了阻断机制。
如果客户端在 60 秒内没有收到来自特定对等方的任何消息,它将假定自己已被“冷落”。
秉承着针锋相对的心态,我们进行报复并拒绝向该同伴上传(除非他们成为乐观的解脱者)。
然后,对等方将增加乐观解除阻塞的次数,以更快地找到新的连接。
🤔 如果我们仅上传怎么办?
我们发现,使用 BitTorrent 中实现的阻塞算法,我们会优先选择对我们友好的用户。如果我能从他们那里快速下载,我们也会允许他们从我这里快速上传。
如果没有下载怎么办?那么使用这种阻塞算法就无法知道需要解封哪些对等体。当下载完成后,我们会使用新的阻塞算法。
这种新的阻塞算法可以解除上传速率最高的节点的阻塞。这确保了数据片段能够更快地上传,并且能够更快地复制。
具有良好上传速率的对等体也没有被其他对等体服务。
🐝 什么是追踪器?
跟踪器是一种特殊类型的服务器,有助于同行之间的通信。
BitTorrent 中的通信非常重要。我们如何知道其他节点的存在?
追踪器知道谁拥有该文件以及拥有多少。
一旦点对点下载开始,通信就可以在没有跟踪器的情况下继续。
自从创建了无跟踪器种子的分布式哈希表方法以来,BitTorrent 跟踪器在很大程度上是多余的。
🗼 公共追踪器
这些是任何人都可以使用的追踪器。
海盗湾运营着最受欢迎的公共追踪器之一,直到 2009 年将其禁用,仅选择磁力链接(即将讨论)。
🔐 私人追踪器
私人追踪器是私密的。它们要求用户在网站上注册,以限制其使用。控制注册的方法通常是邀请系统。要使用此追踪器,我们需要获得邀请。
🔢 多轨道种子
多跟踪器种子是指单个种子文件中包含多个跟踪器。这样可以提供冗余,即使一个跟踪器发生故障,其他跟踪器仍可继续维护种子的集群。
这种配置可能会导致单个种子文件出现多个未连接的集群,这很不妙。有些用户可以连接到某个特定的跟踪器,但无法连接到另一个跟踪器。这会创建一个不相交的集群,从而降低种子文件传输其所描述文件的效率。
🧲 磁力链接 - 无追踪器种子
之前,我谈到了海盗湾如何摆脱追踪器并开始使用无追踪器的种子。
当我们下载一个种子文件时,我们会得到该种子文件的哈希值。为了在没有 Tracker 的情况下下载该种子文件,我们需要找到其他也在下载该种子文件的节点。为此,我们需要使用分布式哈希表。
让我们探索分布式哈希表。
🐍 分布式哈希表
分布式哈希表 (DHT) 提供了类似字典的接口,但节点分布在网络中。DHT 的诀窍在于,通过对特定键进行哈希运算来找到存储该键的节点。
实际上,每个对等点都成为一个微型追踪器。
每个节点(实现 DHT 协议的客户端/服务器)都有一个唯一的标识符,称为“节点 ID”。我们从与 BitTorrent 信息哈希相同的 160 位空间中随机选择节点 ID。
Infohashes是以下 SHA-1 哈希值:
- ITEM:长度(大小)和路径(带有文件名的路径)
- 名称:要搜索的名称
- 片长:单片的长度(尺寸)
- 片段:此种子每个片段的 SHA-1 哈希值
- Private:限制访问的标志
我们使用距离度量来比较两个节点 ID 或一个节点 ID 和一个信息哈希的“接近度”。
节点必须有一个路由表,其中包含其他几个节点的联系信息。
DHT 中的节点彼此了解。它们知道很多 ID 与自己接近的节点,但很少知道 ID 相距较远的节点。
距离度量是 XOR 并被解释为整数。
$$距离(A,B)= |A \oplus B |$$
值越小,距离越近。
当一个节点想要为一个 torrent 寻找对等点时,它们使用距离度量来将 torrent 的信息哈希与其路由表中的节点 ID 进行比较,或者将一个节点的 ID 与另一个节点的 ID 进行比较。
然后,它们联系路由表中距离信息哈希最近的节点,并向它们询问下载该种子的对等方的联系信息。
如果被联系的节点知道该 torrent 的对等节点,它会在响应中返回对等节点的联系信息。否则,被联系的节点必须返回其路由表中与该 torrent 的 infohash 最接近的节点的联系信息。
原始节点会查询距离目标 infohash 更近的节点,直到找不到更近的节点。当节点搜索完毕后,客户端会将自身的对等联系信息插入到 ID 最接近 torrent infohash 的响应节点上。这样,以后其他节点就可以轻松找到我们了。
对等点查询的返回值包含一个不透明的值,称为“令牌”。对于一个节点,要宣布其控制对等点正在下载 torrent,它必须在最近的对等点查询中显示从同一查询节点接收到的令牌。
当一个节点尝试“宣布”一个种子时,被查询的节点会根据查询节点的 IP 地址检查令牌。这是为了防止恶意主机为其他主机注册种子。
查询节点将令牌返回给其接收令牌的同一节点。令牌分发后,我们必须在合理的时间内接受令牌。BitTorrent 实现使用 IP 地址的 SHA-1 哈希值,该哈希值与每五分钟更改一次的密钥相连接,并且接受最多十分钟前已存在的令牌。
📌 路由表
每个节点都会维护一个已知良好节点的路由表。我们使用路由表的起始点在 DHT 中进行查询。当其他节点查询时,我们会返回路由表中的节点。
我们了解的节点并非都一样。有些节点是“好的”,有些则不然。许多使用 DHT 的节点可以发送查询并接收响应,但无法响应来自其他节点的查询。每个节点的路由表必须仅包含已知的“好”节点。
良好节点是指在过去 15 分钟内响应过我们的查询的节点。如果一个节点在过去 15 分钟内响应过我们的查询并向我们发送过查询,则该节点也属于良好节点。如果节点 15 分钟内不活动,则该节点将变为可疑节点。如果节点连续多次未能响应查询,则该节点将变为不良节点。我们认为良好的节点优先于状态未知的节点。
路由表覆盖了从 0 到2160 的整个节点 ID 空间。我们将路由表细分为多个“桶”,每个桶覆盖该空间的一部分。
一个空表有一个 bucket,其 ID 空间范围为 min=0, max=2 160。
空表只有一个桶,因此任何节点都必须能放入其中。每个桶最多只能容纳 K 个节点,目前为 8 个,之后就会“满”。
当一个 bucket 中充满了已知的良好节点时,除非我们的节点 ID 在该 bucket 的范围内,否则我们不会再添加任何节点。该 bucket 将被两个 bucket 替换,每个 bucket 包含旧 bucket 的一半。旧 bucket 中的节点将分布到新的 bucket 中。
对于只有一个 bucket 的新表,我们总是将满 bucket 分成两个新 bucket,分别覆盖范围 0..2 159和 2 159 ..2 160。
当桶里装满了好节点时,我们直接丢弃新节点。当桶里的节点变坏(如果确实如此)时,我们会用新节点替换它们。
如果节点被视为可疑,并且在过去 15 分钟内未曾被 ping 过,则会对最近最少出现的节点进行 ping 操作。该节点要么响应,要么不响应。如果响应,则我们转到下一个节点。如此循环,直到找到一个未响应的节点。如果没有找到,则认为该存储桶是正常的。
当我们找到一个时,我们会再试一次,然后丢弃该节点并用新的好节点替换它们。
每个存储桶都应保留“上次更改”属性,以显示内容的“新鲜度”。
当存储桶中的节点被 ping 并响应时,或者将节点添加到存储桶中,或者将节点替换为另一个节点时,存储桶的最后更改属性将被更新。
如果最后更改的属性在过去 15 分钟内未更新,则刷新存储桶。
🤺 对 BitTorrent 的攻击
BitTorrent 网络很少受到攻击。一切都是公开的。我们的 IP 地址,我们正在下载的内容——一切。
为什么要攻击一个开放的网络?
为什么要攻击完全开放的网络?
Exploit-DB(一个针对服务的已知漏洞数据库)中仅列出了 7 条记录。其中大多数与特定客户端相关。
针对 BitTorrent 网络的主要攻击目的是阻止盗版。我们之前一直没有提到盗版,但盗版往往与 BitTorrent 同义。
针对 BitTorrent 的主要攻击是Torrent Poisoning。
洪流中毒
此类攻击的目的是获取盗版内容的同行的 IP 地址或以某种方式毒害内容。
麦当娜的《美国生活》专辑发行就是内容中毒的一个例子。发行前,专辑中发布的曲目长度和文件大小都差不多。曲目中有一小段麦当娜的发言:
“你他妈到底在干什么?”
接下来是几分钟的沉默。
以下是一些毒害种子文件的方法。
索引中毒
该索引允许用户定位具有所需内容的对等点的 IP 地址。这种攻击方法使得搜索对等点变得困难。
攻击者在索引中插入大量无效信息,以阻止用户找到正确的信息。
这个想法是通过让对等方尝试从无效对等方下载片段来减慢下载速度。
诱饵插入
他们将损坏的文件版本插入网络。
想象一下,一个文件有 500 份副本,但其中只有 2 份是真实文件,这可以阻止盗版者找到真实文件。
大多数提供种子列表的网站都设有投票系统。这可以阻止此类攻击,因为搜索结果顶部都充满了未损坏的文件。
然而,大多数提供种子列表的网站都设有投票系统。
这可以阻止这种攻击,因为搜索的顶部充满了未损坏的文件。
在《GameDevTycoon》中,文件在首次上传到盗版网站之前就已经发布。盗版者并不知道,文件已被损坏。在盗版版本中,玩家不可能赢得游戏。其他一切都完美无缺。
🧙🏼♂️ 防御黑暗 Bittorrent 攻击
大多数热门种子都是由多年来建立良好关系的个人或团体发布的。在私人追踪器上,可以指向个人。有毒种子很快就会被标记,发布者可能会被封禁。
或者,在公共 Tracker 上,最好下载由受信任的组织制作的种子。毕竟,你是想从 Ubuntu 团队下载 Ubuntu,还是想从用户 xxx-HACKER-ELITE-GHOST-PROTOCOL-xxx 下载?
在公共追踪器上,如果某个种子被污染,该种子就会被举报并删除。
防御 BitTorrent 攻击最简单的方法是使用与您无关的 IP 地址。无论是通过 VPN 还是其他服务。
👋🏻 结论
以下是我们了解到的内容:
- Torrent 描述文件是什么
- BitTorrent 如何选择对等节点
- BitTorrent 如何选择片段
- 以牙还牙算法
- 追踪器
- 对 BitTorrent 网络的攻击
您可以选择做以下一些事情:
文章来源:https://dev.to/brandonskerritt/how-does-bittorrent-work-a-plain-english-guide-16a2