BitTorrent详解
一、什么是BitTorrent
一般来说,我们认为BitTorrent是一个P2P下载软件(点对点下载软件),你在下载的同时,也在为其他用户提供该文件的上传,因为大家是“互相帮助”,所以不会随着用户数的增加产生服务器拥塞而降低下载速度。
但是严格的来说,BitTorrent是一种用来在网络上传输文件的协议(Protocol),它本质上是分布式系统的P2P(点对点)传输文件协议,用户直接相连,然后互相发送和接收文件的各部分,BitTorrent仍然有一个中心服务器(Tracker)(此处的服务器不是指实体的服务器,只是表示提供服务的服务者)来协调各个用户之间的协作。Tracker服务器只是管理连接,对发布的文件内容并不关心,也不传输文件内容,因此Tracker可以用很少的带宽就可以支持大量的用户。BitTorrent的关键思想是用户在下载(入埠传输)时也应该上传(出埠传输),因此网络带宽就能被充分的利用,因此参与下载的用户数量越多,下载速度也越高。
现在 BitTorrent的DHT网络(分布式哈希表Distributed Hash Table)技术,对一个用户来说,它获得一个使用DHT网路的种子后,运行 BitTorrent客户端进行下载后,BitTorrent客户端就会在DHT网路中搜索。连入DHT网络的用户叫做节点(node),节点之间互相有路由记录,因此只要和任何一个已经在DHT网络中的节点连接上,客户端就可以寻找到更多的节点,从而连入网络。一般种子上都有默认节点,那么可以帮助没有连入网络的用户通过那些节点连入网络,如果下载者已经连入DHT网络了,种子里填写的节点就不需要了。因为DHT网络是分布式存储系统,所以连Tracker中心服务器都不需要了(虽然没有连入DHT网络的用户需要找到第一个节点,之后才能连入DHT网络,不过之后用户就可以进行分布式查询了,而不需要向Tracker服务器不断的查询)。
二、BitTorrent与其它文件传输协议的比较
最一般的文件传输协议是客户端/服务器(C/S)模式,比如:HTTP和FTP等下载方式,它们一般都是首先将文件放到服务器上,然后再由服务器传送到每位用户的机器上,即用户机只与服务器相连,客户机之间并不通信。因此如果同一时刻下载的用户数量太多,势必影响到所有用户的下载速度,如果某些用户使用了多线程下载,那对带宽的影响就更严重了,因此几乎所有的下载服务器都有用户数量和最高下载速度等方面的限制,且用户越多,服务器上需要的带宽就越大。很明显,由于上述的原因,即使你使用的是宽带网,通常也很难达到运营商许诺的最高下载速度,这里面固然有网络的原因,但与服务器的限制也不无关系。
另外一种比较流行的文件传输协议是基于点对点(P2P)网络,比如Kazaa、eDonkey、 Gnutella和Direct Connect等,使用这些软件网络用户可以直接连接到其他网络用户,而不需要连接到特定服务器,但由于用户操作系统的限制,发布者可能不能响应很多的用户请求,发布的内容也完全由用户自己决定,可能会涉及到法律和道德问题。
BitTorrent服务是通过一种类似于传销的方式来实现文件共享的,用户帮助服务器分发档案,从而减小服务器的负担。举个例子来说,例如BT服务器将一个文件分成了N个部分,有甲、乙、丙、丁四位用户同时下载,那么BT客户端并不会完全从服务器下载这个文件的所有部分,而是根据实际情况有选择地从其他用户的机器中下载已下载完成的部分。例如甲已经下载了第1部分,乙已经下载了第2部分,那么丙就会从甲的机器中下载第1部分,从乙的机器中下载第2部分,当然甲、乙、丁三位用户也在同时从丙的机器中下载相应的部分,这就大大减轻了BT服务器的负荷,也同时加快了丙的下载速度,也就是说每台参加下载的计算机既从其他用户的计算机上下载文件,同时自身也向其他用户提供下载,因此参与下载的用户数量越多,下载速度也越高。
当然,为了实现上述原理的快速分发,用户需要使用BT客户端进行下载,此外还需要有辅助服务器帮助用户互相连接,也就是Tracker。
三、BitTorrent的系统结构
1、WWW服务器(或者其它能让最终用户获得种子文件的服务):提供上传和下载Torrent种子文件的功能。
2、Tracker:Tracker 是指运行于服务器上的一个服务程序,也称 Tracker服务器。这个程序能够追踪到底有多少人同时在下载或上传同一个文件。客户端连上Tracker服务器,就会获得一个正在下载和上传的用户的信息列表(通常包括IP地址、端口、客户端ID等信息),根据这些信息,BT客户端会自动连上别的用户进行下载和上传。
3、最终用户web浏览器(或者其它能让最终用户获得种子文件的软件):提供上传和下载Torrent种子文件的功能。
4、最终用户下载软件:泛指指运行在用户自己电脑上的支持BitTorrent协议的程序。
5、Seed(****info file) :Torrent种子文件,扩展名为.torren,,在制作完torrent文件后,发布者可以使用 BitTorrent下载客户端,进行Seed他们将会被加进 Tracker服务器的列表,其他人就可以从他那里下载文件了。其包含了一些 BT下载所必须的信息:资源的名称,如果是资源是以目录形式,还有目录树中每个文件的路径信息和文件名;如果资源是单个文件,这个文件的大小信息;如果是以目录形式,目录树中每个文件的大小;对资源实际文件按照固定大小进行分块后每块进行SHA1 hash运算得到的若干特征值的集合;Torrent文件的创建时间、制作者填写的注释、以及制作者的信息等;至少一个Announce地址(除非有 DHT网络),对应于Internet上部署的一个Tracker服务器。有这个文件,用户才可以下载别人发布的东西。Torrent文件通常很小,大约几十K、几百K大小不等。
四、BitTorrent的基本工作原理与流程
1、首先三中的1—5的功能必须具备,实际当中说源文件发布软件与最终用户下载软件就是一个软件(以下简称BT客户端),发布Torrent种子文件也是通过WWW方式,因为WWW方式最为普及,也便于查询,下面的介绍也是以WWW为标准。
2、现在想发布资料件的用户(上传者)需要用BT客户端制作Torrent种子文件,制作种子文件需要指定要发布的文件或者文件夹、Tracker服务器地址(Announce URL)、是否启用DHT网络(什么是DHT网络将在后面说明)、发布者信息等,Torrent种子文件制作软件将要发布的内容分成若干块(每块大小相同,一般为256KB或者1MB),然后计算每块的哈希值(BitTorrent是使用的SHA1哈希软法),该哈希值是用来区分不同的分块的,Torrent种子文件主要包括announce 记录、文件信息、文件名、目录名长度、最后是片段长度、片段的 Sha1 校验码等信息(见Torrent种子文件格式)。
3、现在上传者就可以把Torrent种子文件上传到到WWW服务器,实际上Tracker一般都是内嵌WWW服务器的,也就是上传Torrent种子文件到Tracker服务器,现在BT客户端就可以上传资料了。
4、当其它下载用户(BT客户端)下载到Torrent种子文件后,BT客户端就根据 Torrent种子文件中的Announce 记录找到Tracker服务器地址,BT客户端连接到Tracker服务器(Tracker服务器提供服务的方式大部分都是HTTP兼容的,但也有使用 UDP的),发送Torrent种子文件的哈希信息和其它一些信息(见BT客户端请求格式),Tracker服务器查找该哈希信息,如果找不到就作出相应的处理,如返回错误信息或者断开连接。
5、如果在步骤4找到该哈希信息,Tracker服务器就会反连(NatCheck)客户的IP地址和端口这样就可以区分内网用户还是公网用户(如果是内网用户,它是连不通的,因为它会连到Nat服务器或者路由器上,结果就是连不通),然后服务器返回现在正在下载这个文件的所有公网用户的IP地址和端口列表,返回给BT客户端(也可能是部分客户列表),最后如果该用户是公网用户 Tracker服务器会把用户提交的IP地址和端口保存下来,这样其它人就可以找到该用户。
6、上面说到Tracker服务器只会返回公网的IP地址,现在来解释一下内网用户如何上传数据,因为BT是一个主动连接的软件(即使已经下载完了,也不也会主动连接他人)下面是一个仿真流程:
1)内网用户开始做Seed
2)服务器收到请求,由于是第一个所以也没有Peer(对端,只一个TCP连接的一方)返回
3)公网用户提交请求,由于Seed是内网用户所以也没有Peer返回,等待下载,但服务器会把它的IP放到列表中
4)内网经过设定的时间间隔后,再向服务器放出请求,得到上面得公网IP
5)得到公网IP后,内网马上进行连接
6)公网用户建立连接,数据开始传输 (实际上现在是公网用户做服务器,内网用户做客户端)
7)其它内网用户去上面公网用户下载数据
7、BT客户端得到这些其他用户IP后,就可以直接连接到这些IP和端口下载资料了。BT客户端会到所有的用户去寻找自己要下载的东西。BT客户端每找到一个用户就建立一个Socket来下载,所以下载的人越多,速度就越快。
BT 客户端下载一个文件并不是从一个服务器下载,而是通过中心Tracker服务器找到其他用户,然后从不同用户下载文件的不同部分,也就是实现分布式下载,不过有中心服务器(Tracker服务器)协调的分布式下载使系统更有效率,可能Tracker服务器会成为瓶颈,但是由于BT客户端的查询内容简单并且不是连续的查询Tracker服务器,这就相当于增加Tracker服务器的负载能力。
五、Torrent文件(****info file)格式
Torrent文件格式使用了bencoding的数据表达方法,支持四种数据格式:字符串、整数、列表、字典。一个Torrent文件就是一个经过编码的bencoding字典。
Bencoding格式如下:
对于字符串,首先是一个字符串的长度,然后是冒号,后面跟着实际的字符串,例如:4:spam,就是“spam”。
整数编码如下,以 ‘i’开始,然后10进制的整数值,最后以’e’结尾。例如,i3e表示3,I-3e表示-3。整数没有大小限制。I-0e是无效的。除了 i0e外,所有以0起始的整数都无效。I0e当然表示0。
列表编码如下,以’l’开始,接下来是列表值的编码(也采用bencoded编码),最后以’e’结束。例如:l4:spam4:eggse 表示 [‘spam’,‘eggs’]。
字典编码如下,以’d’开始,接下来是可选的keys和它对应的值,最户以’e’结束。例如:d3:cow3:moo4:spam4:eggse,表示{‘cow’:’moo’,’spam’:’eggs’},而 d4:spaml1:al:bee 表示 {‘spam’:[‘a’,’b’]}。键值必须是字符串,而且已经排序(并非是按照字母顺序排序,而是根据原始的字符串进行排序)。
1、Torrent文件基本格式
l info
包含文件信息的一个字典。info有单文件和多文件两种,详细说明见下。
l announce
tracker服务器地址。
l announce-list
可选,包含其他可用tracker服务器地址的列表。
l creation date
可选,torrent文件创建时间,UNIX标准格式,表示自UTC1970年1月1日0时以来的秒数。
l comment
可选,torrent创建者写的备注。
l created by
可选,创建torrent文件的程序名和版本。
除以上外,Torrent文件可能还包含encoding、nodes等内容,大概是由后续版本的BT协议规定的。nodes有可能跟DHT有关。
2、Info字典格式
1)Info字典有两种格式,以下为两种共有的部分:
l piece length
每块数据的长度。
l pieces
字符串格式,长度除以20即为总块数,每20字节又表示1块数据的SHA1值。
l private
值为1或0的整数,可选。看不太懂什么意思,似乎是说如该值为1,则只能从torrent文件中指定的tracker服务器找别的peer,不设或为0则不限制。
2)只包含一个文件的Info字典:
l name
文件名。
l length
文件长度。
l md5sum
可选,32字节长的文件MD5值。
3)包含多个文件的Info字典:
l name
存放文件的目录名。
l files
包含多个字典的列表,每个字典表示一个文件的信息。
files列表中的每个字典包含的内容:
l length
文件长度。
l path
包含一个或多个字符串的列表。0到-2个表示文件目录,最后一个表示文件名。例如["dir1", "dir2", "file.ext"]表示文件保存在dir1/dir2子目录下,文件名为file.ext。
六、BT客户端请求格式
Trakcer 通过HTTP的GET命令的参数来接收信息,而响应给对方(也就是下载者)的是经过bencoded 编码的消息。注意,尽管当前的tracker的实现需要一个web服务器,它实际上可以运行的更轻便一些,例如,作为apache的一个模块;而且现在还有使用UDP协议的Tracker服务器。
发送给Tracker的GET请求,包含以下关键字:
Info_hash:
元文件中info部分的sha hash,20字节长。这个字符创几乎肯定需要被转义(译注:在URL中,有些字符不能出现,必须通过unicode进行编码)
Peer_id:
下载者的id,一个20字节长的字符串。每个下载者在开始一次新的下载之前,需要随机创建这个id。这个字符串通常也需要被转义。
IP:
一个可选的参数,给出了peer的ip地址(或者dns名称?)。通常用在origin身上,如果它和tracker在同一个机器上。
Port:
peer所监听的端口。下载者通常在在 6881 端口上监听,如果该端口被占用,那么会一直尝试到 6889,如果都被占用,那么就放弃监听。
Uploaded:
已经上载的数据大小,十进制表示。
Downloaded:
已经下载的数据大小,十进制表示
Left:
该peer还有多少数据没有下载完,十进制表示。注意,这个值不能根据文件长度和已下载数据大小计算出来,因为很可能是断点续传,如果因为检查文件完整性失败而必须重新下载的时候,这也提供了一个机会。
Event:
一个可选的关键字,值是started、compted或者stopped之一(也可以为空,不做处理)。如果不出现该关键字,。在一次下载刚开始的时候,该值被设置为started,在下载完成之后,设置为completed。如果下载者停止了下载,那么该值设置为 stopped。
Tracker的响应是用bencoded编码的字典。如果tracker的响应中有一个关键字failure reason,那么它对应的是一个字符串,用来解释查询失败的原因,其它关键字都不再需要了。否则,它必须有两个关键字:Interval:下载者在两次发送请求之间的时间间隔。Peers:一个字典的列表,每个字典包括以下关键字:Peer id,IP,Port,分别对应peer所选择的id、IP地址或者dns名称、端口号。
七、BitTorrent其它应用分布式系统的相关技术
文件下载片断选择是为了提高系统的总效率,而阻塞算法是为了提高个人用户的公平性和效率,作为取自于用户并用之于用户的分布式系统,整个系统的效率和个人用户的公平性至关重要,BitTorrent的片断下载策略保证了最大的下载效率和稳健的完整性,而阻塞算法鼓励个人用户上传。BitTorrent的阻塞算法并不记录历史,也就是对用户以前的上传、下载行为没有记录,有些最先版本的BitTorrent已经能对帐户的上传、下载信息做出统计,然后转化为积分,但积分还没有和用户的下载优先级绑定,而且积分也只是简单的统计上传流量,上传的内容和上传的目标用户也没有分析,简单的积分策略并不能应对五花八门Spamming技术,积分算法应该是上传和下载流量的比数,且积分增加速度随着上传的不同目标用户和不同上传内容数量的增加而增加。
1、下载文件片断的选择(Piece Selection)
选择一个好的顺序来下载片断,对提高性能非常重要。一个差的片断选择算法可能导致所有的片断都处于下载中,或者另一种情况,没有任何片断被上载给其它 peers。
1)严格的优先级(Strict Priority)
片断选择的第一个策略是:一旦请求了某个片断的子片断,那么该片断剩下的子片断优先被请求。这样,可以尽可能快的获得一个完整的片断。
2)最少的优先(Rarest First)
对一个下载者来说,在选择下一个被下载的片断时,通常选择的是它的peers们所拥有的最少的那个片断,也就是所谓的“最少优先”。这种技术,确保了每个下载者都拥有它的peers们最希望得到的那些片断,从而一旦有需要,上载就可以开始。这也确保了那些越普通的片断越放在最后下载,从而减少了这样一种可能性,即某个peer当前正提供上载,而随后却没有任何的被别人感兴趣的片断了。也就说说,每个peer都优先选择整个系统中最少的那些片断去下载,而那些在系统中相对较多的片断,放在后面下载,这样,整个系统就趋向于一种更优的状态。如果不用这种算法,大家都去下载最多的那些片断,那么这些片断就会在系统中分布的越来越多,而那些在系统中相对较少的片断仍然很少,最后,某些 peer 就不再拥有其它 peer 感兴趣的片断了,那么系统的参与者越来越少,整个系统的性能就下降。
在BT系统中,充分考虑了经济学的概念,处处从整个系统的性能出发,参与者越多,系统越优化。
信息理论显示除非种子上传了文件的所有片断,否则没有任何下载者可以完成所有文件的下载。如果在一个部署中,只有一个种子,而且种子的上载能力比它的大多数下载者都要差,那么,不同的下载者从种子那里下载不同的片断,性能就会变得比较好,因为,重复的下载浪费了种子获取更多信息的机会。“最少优先”使得下载者只从种子处下载新的片断(也就是整个系统中其它peer都没有的片断),因为,下载者能够看到其它peers那里已经有了种子已经上传的片断。
在某些部署中,原始的种子由于某些原因最终关闭,只好由剩下的这些下载者们来负责上传。这样显然会带来一个风险:某些片断任何一个下载者都不拥有。“最少优先”也很好的处理了这种情况。通过尽快的复制最少的片断,减少了这种由于当前的peers停止上载后带来的风险。
3)随机的第一个片断(Random First Piece)
“ 最少优先”的一个例外是在下载刚开始的时候。此时,下载者没有任何片断可供上传,所以,需要尽快的获取一个完整的片断。而最少的片断,通常只有某一个peer拥有,所以,它可能比多个peers都拥有的那些片断下载的要慢。因此,第一个片断是随机选择的,直到第一个片断下载完成,才切换到“最少优先”的策略。
4)最后阶段模式(Endgame Mode)
有时候,从一个速率很慢的peer那里请求一个片断。在下载的中间阶段,这不是什么问题,但是却可能潜在的延迟下载的完成。为了防止这种情况,在最后阶段,peer向它的所有的peers们都发送某片断的子片断的请求,一旦某些子片断到了,那么就会向其它peer发送 cancel 消息,取消对这些子片断的请求,以避免带宽的浪费。实际上,用这种方法并没有浪费多少带宽,而文件的结束部分也一直下载的非常快。
2、阻塞算法(Choking Algorithms)
BT 并不集中分配资源。每个peer自己有责任来尽可能的提高它的下载速率。Peers从它可以连接的peers处下载文件,并根据对方提供的下载速率给予同等的上传回报(你敬我一尺,我敬你一丈)。对于合作者,提供上传服务,对于不合作的,就阻塞对方。所以说,阻塞是一种临时的拒绝上传策略,虽然上传停止了,但是下载仍然继续。在阻塞停止的时候,连接并不需要重新建立。
阻塞算法并不属于BT对等协议(指peers 之间交互的协议)的技术部分,但是对提高性能是必要的。一个好的阻塞算法应该利用所有可用的资源,为所有下载者提供一致可靠的下载速率,并适当惩罚那些只下载而不上传的peers。
1)帕累托效率(Pareto Efficiency)
在经济学里,帕累托效率可以这样来定义:一种状态(资源配置、社会制度等)被称为帕累托最优状态,如果不存在另外一种可选择的状态使得没有任何人的处境变差而至少有一个人的处境变得更好。这意味着,当满足给定的约束条件,一种资源配置的状态已经使没有人能够按照自己的偏好在不损害别人的条件下变得更好,那么就是达到了帕累托最优状态。可以通俗地理解为,如果处于这种状态:除非损人,就不能利己,这就达到了帕累托最优。在计算机领域,寻求帕累托有效是一种本地优化算法BitTorrent的阻塞算法,用一种针锋相对的方式来试图达到帕累托最优。(原文不太好翻译,我简化了)。Peers对那些向他提供上传服务的peers给予同样的回报,目的是希望在任何时候都有若干个连接正在进行着双向传输。
2)BitTorrent的阻塞算法
从技术层面上说,BT的每个peer一直与固定数量的其它 peers 保持疏通(通常是4个),所以问题就变成了哪些peers应该保持疏通?这种方法使得TCP的拥塞控制性能能够可靠的饱和上传容量。(也就是说,尽量让整个系统的上传能力达到最大)。
严格的根据当前的下载速率来决定哪些peers应该保持疏通。令人惊讶的是,计算当前下载速率是个大难题。当前的实现实质上是一个每隔20秒的轮询。而原来的算法是对一个长时间的网络传输进行总计,但这种方法很差劲,因为由于资源可用或者不可用,带宽会变化的很快。
为了避免因为频繁的阻塞和疏通 peers造成的资源浪费,BT每隔10秒计算一次哪个peer需要被阻塞,然后将这种状态保持到下一个10秒。10秒已经足够使得TCP来调整它的传输性能到最大。
3)开放检测(Optimistic Unchoking)
如果只是简单的为提供最好的下载速率的peers们提供上载,那么就没有办法来发现那些空闲的连接是否比当前正使用的连接更好。为了解决这个问题,在任何时候,每个peer都拥有一个称为“optimistic unchoking”的连接,这个连接总是保持疏通状态,而不管它的下载速率是怎样。每隔30秒,重新计算一次哪个连接应该是“optimistic unchoking”。30秒足以让上传能力达到最大,下载能力也相应的达到最大。这种和针锋相对类似的思想非常的伟大。“optimistic unchoking”非常和谐的与“囚徒困境”合作。
4)反对歧视(Anti-snubbing)
某些情况下,一个peer可能被它所有的peers都阻塞了,这种情况下,它将会保持较低的下载速率直到通过 “optimistic unchoking”找到更好peers。为了减轻这种问题,如果一段时间过后,从某个peer那里一个片断也没有得到,那么这个peer认为自己被对方 “怠慢”了,于是不再为对方提供上传,除非对方是“optimistic unchoking”。这种情况频繁发生,会导致多于一个的并发的“optimistic unchoking”。
5)仅仅上传(Upload Only)
一旦某个peer完成了下载,它不能再通过下载速率(因为下载速率已经为0了)来决定为哪些 peers 提供上载了。目前采用的解决办法是,优先选择那些从它这里得到更好的上载速率的peers。这样的理由是可以尽可能的利用上载带宽。