BitTorrent协议规范

BitTorrent是一个用于分享文件的协议,它通过URL来定位文件并且被设计为与web紧密结合。该协议相对于普通HTTP协议的优势是:当有多个节点同时下载同一个文件时,每个节点也会向其他节点上传资源,这使得源文件(file source)只需要比较少的负载就能支持大量用户的下载。

BitTorrent中所包含的实体

  • 一个普通的web服务器
  • 一个静态‘元信息’文件
  • 一个tracker服务器
  • 一个‘原始’下载者
  • 终端用户web浏览者
  • 终端用户下载者

一般来说会有多个终端用户需要下载同一个文件。

为了提供服务,一个主机需要进行以下操作:

  1. 启动一个tracker服务器;
  2. 启动一个普通的web服务器,如apache等;
  3. 在web服务器上将.torrent文件与mime类型application/x-bittorrent关联起来
  4. 通过完整的文件资源和tracker的URL生成一个元信息(.torrent)文件;
  5. 将元信息文件放在web服务器上;
  6. 将元信息文件链接在一些其他的网页上;
  7. 启动一个已拥有完整文件的下载者(原始下载者)。

为了开始下载,一个用户需要进行以下操作:

  1. 安装BitTorrent客户端;
  2. 上网;
  3. 点击一个.torrent文件的链接;
  4. 选择文件的保存位置,或是选择部分文件以恢复下载;
  5. 等待下载完成;
  6. 通知下载者退出(在此之前会保持上传);

bencoding编码

  • 字符串编码:十进制的字符串长度前缀 + ‘:’ + 字符串。如: 字符串‘spam’对应的编码是 4:spam。
  • 整数编码: ‘i’ + 整数的十进制表示 + ‘e’。如:3对应的编码是 i3e,-3对应的编码是 i-3e,整数没有长度限制,除了i0e代表的是数字0之外,所有有前缀0的编码都是无效的(如i03e),而且i-0e也是无效的。
  • 数组编码:’l’ + 编码后的数组元素 + ‘e’。如[‘spam’, ‘eggs’]对应的编码是 l4:spam4:eggse。
  • dictionary编码: ‘d’ + 编码后的dictionary键值对 + ‘e’。如{‘cow’: ‘moo’, ‘spam’: ‘eggs’}对应的编码是d3:cow3:moo4:spam4:eggse,{‘spam’: [‘a’, ‘b’]}对应的编码是d4:spaml1:a1:bee。所有的key必须是string并按序排列(以原字符串排序,而不是字母数字)。

元信息文件

元信息文件(或.torrent文件)是编码后的有以下键值的dictionary:
announce:tracker的URL
info:一个如下所述的dictionary
.torrent文件中的包含文本的字符串都需要经过UTF-8编码。

info dictionary

name:UTF-8编码的字符串,建议的保存文件名。
piece length:文件分割片段的byte数。为了方便传输,文件通常需要分割为多个固定长度的片段,除了最后一个片段可能不满足该固定长度。piece length一般都是2的指数级,最常见的是2^18 = 256K(BitTorrent3.2版本之前默认的piece length是2^20=1M)。
pieces:一个长度为20的倍数的字符串。该字符串可以分割出长度为20的子字符串,每个子字符串都是对应位置的文件片段的SHA1哈希值。
length/files:两个字段不会同时出现.torrent文件中,也不会都不出现。如果出现length,该.torrent文件对应的是一个文件,并且该字段记录的是该文件的byte数;如果出现files,则对应的是多个文件,该字段记录的是每个文件的信息,对应的是一个包含以下键值的dictionary数组:
length-文件的byte数;
path-一个UTF-8编码的字符串数组,对应子文件夹名,数组中最后一个元素代表真实的文件名(数组长度为0则表示出错)。

trackers

tracker的GET请求包含以下字段:
info_hash:元信息文件中info字段经bencoded编码后的20byte SHA1哈希值,该字段的值必须是自动转换的。
需要注意的是该字段的值是通过元信息文件推导出来的,当.torrent文件不是合法文件时(key的顺序错误,有前导0),客户端必须拒绝该文件。文件合法时,则直接截取进行计算。
peer_id:长度为20的字符串,代表下载者的id。在每次开始下载一个新文件时,用户都需要随机生成自己的id。通常该值也是自动转换的。
ip:可选字段,对等方的IP或dns域名,一般是与tracker位于同一台机器的原始下载者用来分发文件的。
port:对等方监听的端口号。一般下载者监听6881端口,被占用则尝试6882,一直到6889,都被占用则放弃。
uploaded:目前已上传的总数,十进制的ASCII码。
downloaded:目前已下载的总数,十进制的ASCII码。
left:对等方还需要下载的byte数,十进制的ASCII码。需要注意的是,该字段的值不能通过文件的长度和downloaded字段的值来计算。因为下载的数据可能无法通过完整性检查而需要重新恢复下载。
event:可选字段,对应started、completed或stopped(或empty)。如果缺省,下载者也会定期发出。下载开始时发送started,下载完成时发送completed,停止下载时发送stopped。

tracker的响应也是bencoded的dictionary。如果响应中包含failure reason字段,该字段将对应一段可阅读的失败原因字符串,并且响应中不需要其他字段。否则响应中必须要包含两个字段:
interval:下载者发送请求的间隔时间(秒)。
peers:一个dictionary列表,每个dictionary包含peer id、ip、port三个字段,分别代表peer的ID、IP地址或DNS域名和端口号。需要注意的是,下载者可能会不规律地重新发送请求以获得更多的peer或有新的event发生时。

更常见的是tracker返回一个peer列表的压缩版,如BEP23

通常请求和响应是通过UDP tracker 协议传输的。

peer 协议

BitTorrent的peer协议是在TCP或uTP上实现的。

Peer连接是双向对称的,每个方向上发送的信息看上去都是一样的,数据流也可以任意方向上传输。

连接双方都会维护一个2bit位的状态信息:choked或not choked,interested或not interested。choked表示在not choked发生前将不会发送任何数据,choked背后的技术和合理性将在下文中介绍。

当连接的一方状态是interested,另一方的状态是not choked时,数据传输才会发生。interested状态必须一直保证实时性-只要一个not choked的对等方没有下载者所需要的资源,即使下载者的状态是choked,也要表明他not interested的状态。这可以保证下载者可以知道哪些not choked的peer会立即开始下载。

下载开始时,状态是choked和not interested。

当数据开始传输时,下载者应该保持多个片段的下载请求在队列中等待以获得比较好的TCP性能(流水线机制)。另一方面,无法直接写入TCP缓存中的请求应该存放在内存的队列中而不是应用层的网络缓存中,这样当choked发生时,请求可以直接被丢弃而不是继续发送。

peer连接协议包含一次握手过程,接着就是不间断的以长度信息为前缀的数据流。握手发送的数据是19BitTorrent protocol,其中19是长度前缀。

之后所有发送的整数都是大端存储的4byte数。

固定头部数据之后是全部为0的8byte的保留位,以做扩展用。

之后是20byte的SHA1哈希值,与info_hash值相同,不过这里是原始值,那里是引用值。如果连接双方该值不同,则终止连接。一个例外是。。。

之后是20byte的peer id,包含在tracker请求中,或是tracker响应的peer list中。如果接收方的peer id与发送方期望的id不同,则终止连接。

这就是握手过程,之后就是长度为前缀的信息流。长度为0的信息用来keepalive,并被忽略。一般每两分钟发送一次keepalive,但在等待数据时很容易超时。

peer messages

所有的非keepalive信息都以一个表示其类型的byte开始。

可能的值有:
- 0 - choke
- 1 - unchoke
- 2 - interested
- 3 - not interested
- 4 - have
- 5 - bitfield
- 6 - request
- 7 - piece
- 8 - cancel

‘choke’、‘unchoke’、‘interested’和‘not interested’都没有载荷。

‘bitfield’只在第一个信息中存在,其载荷为下载者发送片段的信息。已发送片段的索引位置为1,未发送片段的索引位置为0。第一个byte从高位到地位分别对应索引0-7,下一个byte对应8-15,以此类推。最后一个byte的多余位置为0。

‘have’的载荷为一个数字,下载者刚刚完成并检查过哈希值的片段索引。

‘request’的载荷为一个索引、起始位置和长度。长度一般是2的指数级,除了最后一个片段可能不是之外。目前所有的实现都是2^14(16KB),当request的数据大于该值时终止连接。

‘cancel’的载荷与request相同。一般只在下载即将结束时发送,也就是‘endgame mode’期间。当下载即将完成时,剩余片段会有从同一个通信链路上下载的趋向,这会很慢。为了保证最后几个片段下载也很快,下载者还没有决定剩下的片段请求发送给谁时,它将所有片段的请求发给所有人。为了防止过于低效,当某个片段下载完成时就向其他人发送cancel。

‘piece’包含一个索引、起始位置和片段。注意,该信息隐式地与request相关联。当choke或unchoke信息连续快速发送时或传输速度很慢时,可能会有一个不需要的piece到达。

下载者一般以随机顺序下载片段,防止下载者与其他用户拥有相同片段的子集或超集。

发生choke有以下原因,当同时发送多个连接时,TCP的拥塞控制表现的并不好。choke也使得每个用户使用tit-for-tat-ish 算法来保证一个一致的下载率。

下文的choking算法是目前正在使用的算法,重要的是所有新算法要在扩展网络中运行良好,也要在包含此算法的网络中运行良好。

一个好的choking算法应该满足几个标准。它应该设置一个同时上传限制以保证好的TCP性能,应该避免频繁的choke和unchoke(颤动),应该供他人下载的用户施以奖励,应该不时地检查未使用的连接以确认是否比当前使用的连接更好(乐观unchoking)。

目前部署的choking算法为避免颤动,每十秒改变其choke状态,unchoke四个有最好下载率且interested的peer来作为奖励并限制上传。有更好的上传率但not interested的peer会unchoke,并且当他们interested时,最差的上传者将被choke。如果一个下载者有完整文件,它将用它的下载率而非上传率来决定unchoke。

对于乐观unchoking来说,任何时刻都有一个unchoke的peer,无论其上传率是多少(如果interested,该peer将作为四个unchoke的下载者之一)。每30秒决定哪个peer将被unchoke。一个新的连接有三倍于其他人的机会被unchoke,以获得一个上传完整片段的机会。

The BitTorrent Protocol Specification by Bram Cohen

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值