Peer wire protocol (TCP)
概述
peer(端)协议使片(piece)的交换变得容易,片的描述请参考元信息文件。
注意:原来的规范在描述peer协议时,也使用术语piece“(片)”,但是这不同于元信息文件里面的术语“piece(片)”,由于这个原因,在本规范中,将使用术语“块(block)”来描述peers(端)之间交换的数据。
一个客户端(client)必须维持其与每一个远程peer(端)连接的状态信息:
l choked: 远程peer(端)是否已经choke本客户端。当一个peer(端) choke本客户端后,它是在通知本客户端,除非它unchoke本客户端,否则它不会应答该客户端所发出的任何请求。本客户端也不应该试图向远程peer发送数据请求,并且应该认为所有没有应答的请求已经被远程peer丢弃。
l interested: 远程peer(端)是否对本客户端提供的数据感兴趣。这是远程peer在通知本客户端,当本客户端unchoke他们时,远程客户端将开始请求块(block)。
注意这也意味着本客户端需要记录它是否对远程peer(端)感兴趣,以及它是否choke/unchoke远程peer。因此真正的列表看起来像这样:
l am_choking: 本客户端正在choke远程peer。
l am_interested: 本客户端对远程peer感兴趣。
l peer_choking: 远程peer正choke本客户端。
l peer_interested: 远程peer对本客户端感兴趣。
客户端连接开始时状态是choke和not interested(不感兴趣)。换句话就是:
l am_choking = 1
l am_interested = 0
l peer_choking = 1
l peer_interested = 0
当一个客户端对一个远程peer感兴趣并且那个远程peer没有choke这个客户端,那么这个客户端就可以从远程peer下载块(block)。当一个客户端没有choke一个peer,并且那个peer对这个客户端这个感兴趣时,这个客户端就会上传块(block)。
客户端必须不断通知它的peers,它是否对它们感兴趣,这一点是很重要的。客户端和每个端的状态信息必须保持最新,即使本客户端被choke。这允许所有的peer知道,当它们unchoke该客户端后,该客户端是否开始下载(反之亦然)。
数据类型
如果没有用其他的方法指定,在peer wire协议中的所有整数都会编码为4个字节的大端(big-endian)值。这也包括在握手之后,所有报文(Message)的长度前缀。
报文流(Message flow)
(译者注:因为ICMP-Internet控制报文协议中的Message翻译成报文,同时IP/TCP层中传输的数据都翻译为数据报,应用层传输的数据都翻译成报文,因此在这里Message翻译成报文)
peer wire协议由一个初始的握手组成。握手之后,peers通过以长度为前缀消息的交换进行通信。长度前缀就是上面描述的整数。
握手(HandShake)
握手是一个必需的报文,并且必须是客户端发送的第一个报文。该握手报文的长度是(49+len(pstr))字节。
握手:handshake: <pstrlen><pstr><reserved><info_hash><peer_id>
l pstrlen: <pstr>的字符串长度,单个字节。
l pstr: 协议的标识符,字符串类型。
l reserved: 8个保留字节。当前的所有实现都使用全0.这些字节里面的每一个字节都可以用来改变协议的行为。来自Bram的邮件建议应该首先使用后面的位,以便可以使用前面的位来改变后面位的意义。
l info_hash: 元信息文件中info键(key)对应值的20字节SHA1哈希。这个info_hash和在tracker请求中info_hash是同一个。
l peer_id: 用于唯一标识客户端的20字节字符串。这个peer_id通常跟在tracker请求中传送的peer_id相同(但也不尽然,例如在Azureus,就有一个匿名选项)。
在BitTorrent协议1.0版本,pstrlen = 19, pstr = “BitTorrent protocol”。
连接的发起者应该立即发送握手报文。如果接收方能够同时地服务多个torrent,它会等待发起者的握手报文(torrent由infohash唯一标识)。尽管如此,一旦接收方看到握手报文中的info_hash部分,接收方必须尽快响应。tracker的NAT-checking特性不会发送握手报文的peer_id字段。
如果一个客户端接收到一个握手报文,并且该客户端没有服务这个报文的info_hash,那么该客户端必须丢弃该连接。
如果一个连接发起者接收到一个握手报文,并且该报文中peer_id与期望的peer_id不匹配,那么连接发起者应该丢弃该连接。注意发起者可能接收来自tracker的peer信息,该信息包含peer注册的peer_id。来自于tracker的peer_id需要匹配握手报文中的peer_id。
peer_id
peer_id长20个字节。至于怎么将客户端和客户端版本信息编码成peer_id,现在主要有两种惯例:Azureus风格和Shadow风格。
Azureus风格使用如下编码方式:’-’, 紧接着是2个字符的client id,再接着是4个数字的版本号,’-’,后面跟着随机数。
例如:'-AZ2060-'...