更多内容来自这里
2.1
BitTorrent(简称BT)是一个文件分发协议,每个下载者在下载的同时不断向其他下载者上传已下载的数据。而在FTP、HTTP协议中,每个下载者从FTP或HTTP服务器处下载自己所需要的文件,各个下载者之间没有交互。当非常多的用户同时访问和下载服务器上的文件时,由于FTP服务器的处理能力和带宽的限制,下载速度会急剧下降,有的用户根本访问不了服务器。BT协议与FTP协议不同,它的特点是下载的人越多下载的速度越快,其原因在于每个下载者将已下载的数据提供给其他下载者下载,它充分利用了用户的上载带宽。BT协议通过一定的策略保证上传的速度越快,下载的速度也越快。
2.2 基于BT 协议的文件分发系统的构成
基于BT协议的文件分发系统由以下几个实体构成。
(1)一个Web服务器。
(2)一个种子文件。
(3)一个Tracker服务器。
(4)一个原始文件提供者。
(5)一个网络浏览器。
(6)一个或多个下载者。
Web服务器上保存着种子文件,下载者使用网络浏览器(如IE浏览器)从Web服务器上下载种子文件。种子文件,又称为元原文件或metafile,它保存了共享文件的一些信息,如共享文件的文件名、文件大小、Tracker服务器的地址。种子文件通常很小,一般大小为1GB的共享文件,其种子文件不足100KB,种子文件以.torrent为后缀。Tracker服务器保存着当前下载某共享文件的所有下载者的IP和端口。原始文件提供者提供完整的共享文件供其他下载者下载,它也被称为种子,种子文件就是提供者使用BT客户端生成的。每个下载者通过运行BT客户端软件下载共享文件。我们把某个下载者本身称为客户端,把其他下载者称为peer。
BT客户端下载一个共享文件的过程是:客户端首先解析种子文件,获取待下载的共享文件的一些信息,其中包括Tracker服务器的地址。然后客户端连接Tracker获取当前下载该文件的所有下载者的IP和端口。之后客户端根据IP和端口连接其他下载者,从它们那里下载文件,同时把自己已下载的部分提供给其他下载者下载。
共享文件在逻辑上被划分为大小相同的块,称为piece,每个piece的大小通常为256KB。对于共享文件,文件的第1字节到第256K(即262144)字节为第一个piece,第256K+1字节到第512K字节为第二个piece,依此类推。种子文件中包含有每个piece的hash值。BT协议规定使用Sha1算法对每个piece生成20字节的hash值,作为每个piece的指纹。每当客户端下载完一个piece时,即对该peice使用Sha1算法计算其hash值,并与种子文件中保存的该peice的hash值进行比较,如果一致即表明下载了一个完整而正确的piece。一旦某个piece被下载,该piece即提供给其他peer下载。在实际上传和下载中,每个piece又被划分为大小相同的slice,每个slice的大小固定为16KB(16384字节)。peer之间每次传输以slice为单位。
从以上描述可以得知,待开发的BT软件(即BT客户端)主要包含以下几个功能:解析种子文件获取待下载的文件的一些信息,连接Tracker获取peer的IP和端口,连接peer进行数据上传和下载、对要发布的提供共享文件制作和生成种子文件。种子文件和Tracker的返回信息都以一种简单而高效的编码方式进行编码,称为B编码。客户端与Tracker交换信息基于HTTP协议,Tracker本身作为一个Web服务器存在。客户端与其他peer采用面向连接的可靠传输协议TCP进行通信。下面将进一步作详细的介绍。
2.3 B编码
种子文件和Tracker的返回信息都是经过B编码的。要解析和处理种子文件以及Tracker的返回信息,首先要熟悉B编码的规则。B编码中有4种类型:字符串、整型、列表、字典。
字符串的编码格式为:<字符串的长度>:<字符串>,其中<>括号中的内容为必需。例如,有一个字符串spam,则经过B编码后为4:spam。
整型的编码格式为:i<十进制的整型数>e,即B编码中的整数以i作为起始符,以e作为终结符,i为integer的第一个字母,e为end的第一个字母。例如,整数3,经过B编码后为i3e,整数−3的B编码为i−3e,整数0的B编码为i0e。
注意i03e不是合法的B编码,因为03不是十进制整数,而是八进制整数。
列表的编码格式为:l<任何合法的类型>e,列表以l为起始符,以e为终结符,中间可以为任何合法的经过B编码的类型,l为list的第一个字母。例如,列表l4:spam4:eggse表示两个字符串,一个是spam,一个是eggs。
字典的编码格式为:d<关键字><值>e,字典以d为起始符,以e为终结符,关键字是一个经过B编码的字符串,值可以是任何合法的B编码类型,在d和e之间可以出现多个关键字和值对,d是dictionary的第一个字母。例如,d4:spaml3:aaa3:bbbee,它是一个字典,该字典的关键字是spam,值是一个列表(以l开始,以e结束),列表中有两个字符串aaa和bbb。
又如:d9:publisher3:bob17:publisher-webpage15:www.example.come,它也是一个字典,第一个关键字是publisher,对应的值为bob,第二个关键字是publisher-webpage,对应的值是www.example.com。
2.4 种子文件的结构
种子文件包含了提供共享的文件的一些信息,它以.torrent为后缀名,种子文件也被称为元信息文件或metafile,它是经过B编码的。种子文件事实上就是一个B编码的字典,它含有以下关键字如表13-1所示。
关 | 含 |
info | 该关键字对应的值是一个字典,它有两种模式,“singel file”和“multiple file”,文件模式和多文件模式。单文件模式是指待共享的文件只有一个,多文件模式是指提供共享的不止一个文件,而是两个或两个以上。如使用BT软件下载一部影片时,影片的上下部可能分别放在不同的文件里 |
announce | 该关键字的值为Tracker的URL |
announce-list | 可选,它的值存放的是备用Tracker的URL |
creation-date | 可选,该关键字对应的值存放的是创建种子文件的时间 |
comment | 可选,它的值存放的是种子文件制作者的备注信息,对于下载来说,该关键字基本没有用处,因此不必理会 |
created by | 可选,该关键字对应的值存放的是生成种子文件的BT客户端软件的信息,如客户端名、版本号等,一般不必理会 |
info是最重要的一个关键字,它的值是一个字典,下面对它再作进一步的介绍。无论是单文件模式还是多文件模式,该字典都包含关键字如表13-2所示。
关 | 含 | |
| l | 每个piece的长度,它的值是一个B编码的整型,该值通常为i262144e,即256K,也有可能为512K或128K |
| l | 对应的值为一个字符串,它存放的是各个piece的hash值,这个字符串的长度一定是20的倍数,因为每个piece的hash值的长度为20字节 |
| l | 该值如果为1,则表明客户端必须通过连接Tracker来获取其他下载者,即peer的IP地址和端口号;如果为0,则表明客户端还可以通过其他方式来获取peer的IP地址和端口号,如DHT方式。DHT即分布式哈希表(Distribute Hash Tabel),它是一种以分布式的方式来获取peer的方法,现在许多BT客户端既支持通过连接Tracker来获取peer,也支持通过DHT来获取peer。如果种子文件中没有private这个关键字,则表明不限制一定要通过连接Tracker来获取peer |
对于单文件模式的种子文件,info的值还含有的关键字如表13-3所示。
关 | 含 |
name | 共享文件的文件名,也就是要下载的文件的文件名 |
length | 共享文件的长度,以字节为单位 |
md5sum | 可选,它是共享文件的md5值,这个值在BT协议中根本没有使用,所以不必理会 |
对于多文件模式的种子文件,info的值还含有的关键字如表13-4所示
关 | 含 |
name | 存放所有共享文件的文件夹名 |
files | 它的值是一个列表,列表中含有多个字典,每个共享文件为一个字典。该字典中含有三个关键词 |
Files的每个共享文件为一个字典字典的关键词如表13-5所示
关 | 含 |
length | 共享文件的长度,以字节为单位 |
md5sum | 可选,同上 |
path | 存放的是共享文件的路径和文件名 |
建议读者到一些提供BT种子文件下载的网站,如bt.greedland.net、www.btchina.net,下载几个种子文件并在Windows操作系统下使用记事本打开进行分析,就可以清楚的了解上述概念。
2.5 与tracker文件的交互
完成解析种子文件并从中获取Tracker服务器的URL后,即可开始与Tracker进行交互。与Tracker进行交互主要有两个目的:一是将自己的下载进度告知给Tracker以便Tracker进行一些相关的统计;二是获取当前下载同一个共享文件的peer的IP地址和端口号。
客户端使用HTTP协议与Tracker进行通信。Tracker通过HTTP GET方法获取请求,请求的构成为Tracker的URL后面跟一个?以及参数和值对,如http://tk.greedland.net/ announce? param1=
在客户端发往Tracker的GET请求中,通常包含参数如表13-6所示。
参 | 含 |
info_hash | 与种子文件中info关键字对应的值,通过Sha1算法计算其hash值,该hash值就是info_hash参数对应的值,该hash值的长度固定为20字节 |
peer_id | 每个客户端在下载文件前以随机的方式生成的20字节的标识符,用于标识自己,它的长度也是固定不变的 |
port | 监听端口号,用于接收其他peer的连接请求 |
uploaded | 当前总的上传量,以字节为单位 |
downloaded | 当前总的下载量,以字节为单位 |
left | 还剩余多少字节需要下载,以字节为单位 |
compact | 该参数的值一般为1。 |
event | 它的值为started、completed、stopped其中之一。客户端第一次与Tracker进行通信时,该值为started;下载完成时,该值为completed;客户端即将关闭时,该值为stopped |
ip | 可选,将客户端的IP地址告知给Tracker,Tracker可以通过分析客户端发给Tracker的IP数据包来获取客户端的IP地址,因此该参数是可选的,一般不用指明客户端的IP |
numwant | 可选,希望Tracker返回多少个peer的IP地址和端口号。如果该参数缺省,则默认返回50个peer的IP地址和端口号 |
key | 可选,它的值为一个随机数,用于进一步标识客户端。因为已经由peer_id来标识客户端,因此该参数一般不使用 |
trackerid | 可选,一般不使用 |
Tracker服务器的返回信息是一个经过B编码的字典。它含有关键字如表13-7所示。
关 | 含 |
failure reason | 该关键字对应的值是一个可以读懂的字符串,指明GET请求失败的原因,如果返回信息中含有这个关键字,就不会再包含其他任何关键字 |
warnging message | 该关键字对应的值是一个可以读懂的警告字符串 |
interval | 指明客户端在下一次连接Tracker前所需等待的时间,以秒为单位 |
min interval | 指明客户端在下一次连接Tracker前所需等待的最少时间,以秒为单位 |
tracker id | 指明Tracker的ID |
complete | 一个整数,指明当前有多少个peer已经完成了整个共享文件的下载 |
incomplete | 一个整数,指明当前有多少个peer还没有完成共享文件的下载 |
peers | 返回各个peer的IP和端口号,它的值是一个字符串。首先是第一个peer的IP地址,然后是其端口号;接着是第二个peer的IP地址,然后是其端口号;依此类推 |
以下是一个发往Tracker服务器的HTTP GET请求的示例:
http://tk.greedland.net/announce?info_hash=01234567890123456789&
peer_id=01234567890123456789&port=3210&compact=1&uploaded=0&downloaded=0&left=8000000&event=started
以下是一个Tracker服务器回应的示例:
d8:completei100e10:incompletei200e8:intervali1800e5:peers300:......e
其中,“......”是一个长度为300的字符串,含有50个peer的IP地址和端口号。IP地址占4字节,端口号占2字节,即一个peer占6字节。
| 发往Tracker服务器的HTTP GET请求中,info_hash和peer_id可能含有非数字、非字母的字符,即含有除0~9、a~z、A~Z之外的字符,此时要对字符进行编码转换。例如,空格应该转换为 。否则Tracker无法正确处理GET请求。 |
2.6 peer之间的通信协议
peer之间的通信协议又称为peer wire protocol,即peer连线协议,它是一个基于TCP协议的应用层协议。
为了防止有的peer只下载不上传,BitTorrent协议建议,客户端只给那些向它提供最快下载速度的4个peer上传数据。简单地说就是谁向我提供下载,我也提供数据供它下载;谁不提供数据给我下载,我的数据也不会上传给它。客户端每隔一定时间,比如10秒,重新计算从各个peer处下载数据的速度,将下载速度最快的4个peer解除阻塞,允许这4个peer从客户端下载数据,同时将其他peer阻塞。
一个例外情况是,为了发现下载速度更快的peer,协议还建议,在任一时刻,客户端保持一个优化非阻塞peer,即无论该peer是否提供数据给客户端下载,客户端都允许该peer从客户端这里下载数据。由于客户端向peer上传数据,peer接着也允许客户端从peer处下载数据,并且下载速度超过4个非阻塞peer中的一个。客户端每隔一定的时间,如30秒,重新选择优化非阻塞peer。
当客户端与peer建立TCP连接后,客户端必须维持的几个状态变量如表13-8所示。
状 态 变 量 | 含 |
am_chocking | 该值若为1,表明客户端将远程peer阻塞。此时如果peer发送数据请求给客户端,客户端将不会理会。也就是说,一旦将peer阻塞,peer就无法从客户端下载到数据;该值若为0,则刚好相反,即表明peer未被阻塞,允许peer从客户端下载数据 |
am_interested | 该值若为1,表明客户端对远程的peer感兴趣。当peer拥有某个piece,而客户端没有,则客户端对peer感兴趣。该值若为0,则刚好相反,即表明客户端对peer不感兴趣,peer拥有的所有piece,客户端都拥有 |
peer_chocking | 该值若为1,表明peer将客户端阻塞。此时,客户端无法从peer处下载到数据。该值若为0,表明客户端可以向peer发送数据请求,客户端将进行响应 |
peer_interested | 该值若为1,表明peer对客户端感兴趣。也即客户端拥有某个piece,而peer没有。该值若为0,表明peer对客户端不感兴趣 |
当客户端与peer建立TCP连接后,客户端将这几个变量的值设置为。
am_chocking
am_interested
peer_chocking
peer_interested = 0。
当客户端对peer感兴趣且peer未将客户端阻塞时,客户端可以从peer处下载数据。当peer对客户端感兴趣,且客户端未将peer阻塞时,客户端向peer上传数据。
除非另有说明,所有的整数型在本协议中被编码为4字节值(高位在前低位在后),包括在握手之后所有信息的长度前缀。