因为最近要开始做有关P2P的项目了,所以开始接触这个领域。
以下这些信息都是我阅读了一些网络上的文章总结出来的,对目前最为流行的三种文件下载工具的工作机制简单总结下。
首先是元老级的BitTorrent。
BT的定义
BitTorrent是一种协议,一种分发文件的协议,通过URL识别内容,可以和WEB进行交互,基于HTTP协议。
BT的原理
简单说就是你在下载一个文件的同时,也在把这个文件上传给别人。一个文件在发布时会被分成很多的文件块,你给予别人你自己拥有的文件块,别人也给予你他们所拥有的文件块。
优势是增加下载的速度,将原本文件发布者所要负载的网络压力均衡给正在下载这个文件的所有用户。
一个BT文件分发系统由以下实体组成:
1 一个普通的web服务器
2 一个静态的“元信息”文件
3 一个跟踪(tracker)服务器
4 终端用户的web浏览器
5 终端下载者
用一个例子来说明BT下载的整个过程
假如有家网络游戏公司,想将自己的网络游戏安装包以BT方式发布,那么他要执行下列步骤:
1 运行一个tracker服务器
2 运行一个web服务器 比如iis或apache
3 在web服务器中 将文件扩展名.torrent和MIME类型 application/x-bittorent关联起来
4 根据tracker服务器的URL和要共享的文件来创建一个“元信息”文件(.torrent文件)
5 将“元信息”文件发布到web服务器上
6 在某个web页面上添加一个到“元信息”文件的链接
7 运行一个BT客户端 该BT客户端已经拥有了完整的文件(网络游戏安装包),该下载者被称为“Origin”或“Seed”,“种子”。
这时有一个网络游戏玩家,被网游公司蛊惑,准备下载该游戏玩下,要执行下列步骤:
1 安装一个BT客户端
2 访问提供.torrent元文件的web服务器
3 点击到.torrent元文件的链接
4 BT客户端询问要保存在哪个目录之类的
5 等待下载完成 结束BT软件 如不结束该软件 将一直向其他下载者提供上传
各个部分之间的连通性
1 web服务器负责提供一个.torrent文件
2 trackers服务器负责从所有的下载者那里接收信息,并且返回它们一个随机的peers的列表,这个交互是通过HTTP或HTTPS协议来完成。
3 下载者周期性的向trackers服务器汇报他们的下载进度,并索取最新的peers。
4 获取peers的下载者,使用基于TCP的BitTorrent协议互相连接到这些peers。
5 origin在这个过程中不下载 只是上传 因为他已经拥有了完整的文件。origin是必须的。
从以上信息中可以看出,trackers服务器是整个下载过程中最为繁忙的服务器,它的繁忙并不是持续连接的负载压力,而是非常频繁和大量的请求。
有关Bencoding编码格式
无论是web服务器提供的那个.torrent文件,还是peers和trackers进行的信息交互,都是基于Bencoding格式的。
Bencoding格式如下:
1 字符串:首先是字符串长度,然后是一个:号,接着是串内容,比如5:hello,就是指hello这个字符串。
2 整数:以“i”开头(int的意思),然后是十进制数字,最后是一个“e”结尾,如i3e表示3,i-3e表示-3,i0e表示0,i-0e是非法的。
3 列表:以“l”开头(list的意思),以“e”结尾。比如 l5:hello5:worldi1234ee 代表 ["hello","world",1234]
4 字典:以“d”开头(dictionary),以“e”结尾。比如 d3:cow3:moo4:spam4:eggse,则代表{"cow":"moo", "spam","eggs"}
元文件(.torrent文件)
.torrent文件(元文件)就是一个采用Bencoded编码的字典,包括以下的keys
1 announce: trackers服务器
2 info: 是一个字典,包括下面几个keys
(1) Name:一个字符串,在保存文件的时候作为一个建议值,仅仅是建议值,你可以用别的名字来保存该文件
(2) Piece length:该文件被分隔成等长的片段,这个值就是片段的大小,片段的大小几乎一直是2的幂。最常用的大小是256K
(3) Pieces: 一个长度为20的整数倍的字符串。它将被分隔为20字节长的多个字串,每个字串都是相应片段的Hash值。比如一个文件被分割成5份,该字串的长度就是5*20 = 100.
(4) length: 出现该key时表示要下载的是单个文件,这个key的值是文件的长度。
(5) files: 是一个字符串,该字符串将被分解成多个字典,每个字典代表了一个文件的信息,这些信息的key分别是length,path,name
tracker查询
tracker通过HTTP的GET命令的参数来接收信息,而相应给对方的是经过bencoded编码的消息。
你可以使用asp或asp.net或php等等技术来实现tracker服务器,但是也可以更加轻便,比如写一个apache的模块或者iis的isapi来实现。
发送给tracker的GET请求包括这些keys:
1 Info_Hash:元文件中info部分的sha hash,20字节长。这个字符串一般都会需要转义(在url中有些字符不能见,必须使用urlencode)
2 Peer_id: 下载者的id,一个20字节长的随机字符串,这个字符串一般也需要转义。
3 Ip:一个可选参数,给出了peer的IP。
4 Port: peer所监听的端口。下载者通常在6881端口上监听,如果该端口被占用,那么会一直尝试绑定到6889,如果都被占用则放弃监听。
5 Uploaded: 已经上传的数据量
6 Downloaded: 已经下载的数据量
7 Left: 该peer还有多少数据没有下载完 这个值不能根据文件长度和已下载数据大小计算出来 因为很可能这次下载是断点续传
8 Event: 可选的关键字 值是 started completed 或 stopped之一。如果没有该关键字,在一次下载刚开始的时候,被设置为started,下载完成后设置成为completed,如果停止了下载,则设置为stoped。
tracker响应
tracker的响应是用bencoded编码的字典。
failure reason:那么它对应的是一个字符串,用来解释查询失败的原因,其他关键字都不需要了。
interval: 下载者在两次发送之间的时间间隔。
peers: 一个字典的列表,每个字典包括peer id, Ip, Port。
BT对等协议
对等协议基于TCP,是peer与peer之间交换信息的协议。
对等的两个协议是对称的,消息在两个方向上同样的传递,数据也可以在任何一个方向上流动。
一旦某个peer下载完一个片段,并且检查了它的完整性,那么它就向他所有的peers宣布他拥有了这个片段。
连接的任何一端都包含两比特的状态信息,是否choked,是否感兴趣。choking是通知对方没有数据可以发送,除非unchoking发生。
一旦一端状态变为interested,另一端变成非choking,传输就开始了。也就是说一个peer如果想从它的某个peer获得数据,他先发送一个消息过去,将连接状态改为interested,接收到该消息的peer,先检查是否该给这个peer发送数据,如果他对这个家伙是unchoke,那么就可以给他发数据,否则不能给他发数据。Interested状态必须一直被设置。
对等协议由一个握手开始,后面是循环的消息流,每个消息前面都有一个数字来表示消息的长度。握手的过程首先是先发送19,然后发送“BitTorrent protocol”19就是它的长度。
后续的所有整数都采用big-endian来编码为4个字节。
在协议名称开始后,是8个保留的字节,这些自己都是0.
接下来对元文件的Info信息进行sha hash,得到20字节长的字串。接收消息方,也会对info进行hash运算,如果结果不一样,说明对方要的文件不是自己提供的,切断连接。
接下来是20字节长的peer id。
这个过程就是握手过程。
其他类型的消息,都有一个字节长的消息类型,可能的值如下:
choke, unchoke, interested, not interested。
bitfield 永远也仅仅是第一个发送的消息,数据实际上是一个位图,如果downloader已经发送了这个片段,那么对应的位置1,否则置0。downloader如果一个片段也没有,可以忽略这个消息。
have 后面的数据是一个简单的数字,是下载者刚刚下载完并检查过完整性的片段的索引。
request 后面包含索引,开始位置和长度,长度是2的幂,当前的实现都使用256.
cancel 在下载就要完成的时候,为了尽快完成,该peer向所有的peer请求数据,当数据下载完成后,向那些请求的peer发送一个cancel,意思是我已经下载下来了,不要再给我了,当然不用发送一个thanks 呵呵
piece 后面包括索引号,开始位置和实际的数据,这种数据和request消息之间有潜在的联系,通常有了request消息后,才会响应piece消息。如果choke和unchoke消息发送的过于迅速,或者传输速度变得很慢,那有可能读到一些不是所期望的片段。
![](https://img2024.cnblogs.com/blog/35695/202408/35695-20240826070647288-243310440.jpg)