Peer wire protocol (TCP) Peer连接协议

Peer wire protocol (TCP) Peer连接协议
总览
peer协议就是用来交换torrent描述文件里定义的piece。

注:原来这里用了术语piece,但是实际上piece用在描述文件里的片,而block才是实际传输中的块。

一个client必须维护状态每个远程peer的每个连接的状态信息,状态如下:

choked: 拒绝,可以理解为阻塞。远程peer是否拒绝(choked)了自己client。当一个peer拒绝(choked)了client,没有任何请求被回 应,除非是解除了拒绝状态(unchoked)。client不去尝试发送块(block)请求,它将认为远程peer丢弃所有没响应的请求。
interested: 可以接受,有兴趣的(这个翻译比较奇怪)。允许client回应块(block)请求。
注:这也暗示保持跟踪远程peer状态。状态类似以下列表:

am_choking: client拒绝peer
am_interested: client可以接受peer
peer_choking: peer拒绝client
peer_interested: peer可以接受client
Client的连接开始状态是"choked" and "not interested".:

am_choking = 1
am_interested = 0
peer_choking = 1
peer_interested = 0
如果client可以接受一个peer,并且peer没有拒绝,client就下载一个块(block) 。如果client没有拒绝peer并且peer也可以接受client,client就上传一个块(block) .

维护好状态是非常重要的。要注意时效性。

数据类型
除非特殊说明,整型是4字节,在握手之后,所有消息都包括了长度前缀,即首先发送消息长度。

消息流
一开始进行初始化握手,之后每个消息前有一个长度前缀,长度是一个整型。

握手
握手消息是必须的,而且必须是第一个消息。

handshake: {pstrlen}{pstr}{reserved}{info
_hash}{peer_id}
pstrlen:  pstr的长度, 单字节
pstr: 协议的字符串标志
reserved: 保存8字节。一般为0. 可以扩展用。
info_hash: 描述文件中20字节的SHA1哈希。这个值跟tracker的参数是一样的。
peer_id: client的20字节唯一标志。还是跟tracker里是一样。
目前1.0协议中, pstrlen=19, and pstr="BitTorrent protocol".

连接的发起人必须立刻发起握手协议,然后等待回应。回应必须立刻返回。tracker的NAT检查功能不放在握手的peer_id中发送。

如果一个client收到一个握手,但是不能提供服务,必须立刻关闭这个连接。

如果连接的发起人收到一个握手,但是其中的peer_id跟自己的匹配不上。那么发起人就关闭这个连接。注:发起人可能从tracker收到peer信息,其中的peer_id是peer注册的,因此必须要匹配。

peer_id
包括了client信息和版本信息peer_id,有两种形式: Azureus-style and Shadow's-style.

Azureus-style 格式: '-', 两个字符代表client id,4个数字代表了版本, '-', 后面就是随机数字.

例: '-AZ2060-'...

已知客户端的格式:

'AZ' -  Azureus
'BB' -  BitBuddy
'CT' -  CTorrent
'MT' -  MoonlightTorrent
'LT' -  libtorrent
'BX' - Bittorrent X
'TS' -  Torrentstorm
'TN' - TorrentDotNET
'SS' - SwarmScope
'XT' -  XanTorrent
'BS' -  BTSlave
'ZT' -  ZipTorrent
'AR' -  Arctic
'SB' - Swiftbit
'MP' -  MooPolice
'lt' -  libTorrent
'BC' -  BitComet
'QT' - Qt 4 Torrent example
'UT' -  μTorrent?
'SZ' -  Shareaza
'RT' -  Retriever
Shadow's style 格式:一个字母作为客户端标志, 三个数字作为版本, '----',后面就是随机数字

例: 'S587----'...

已知客户端的格式:

'S' -  Shadow's client
'U' -  UPnP NAT Bit Torrent
'T' -  BitTornado
'A' -  ABC
'O' -  Osprey Permaseed
Bram's client 现在用这种格式:'M3-4-2--'.

 BitComet 有一些不同. peer_id有四个字符'exbc', 接下来两个字节x和y, 最后是随机字符. 版本号 x和y. 0.59版本后改为Azureus-style. 所以x总是0.

大多种客户端使用随机数字。

附一个比较简单的中文协议:http://www.51cto.com/html/2005/1230/15923.htm

消息(Messages)
所有的消息格式都是这样的:<内容长度前缀><消息ID><有效内容>. 内容长度前缀是4字节,大尾格式. 消息ID是单个十进制字符. 有效内容根据消息种类不同而不同(费话).

注:内容长度是整型,原文four byte big-endian values,意思是4个字节,大尾格式,高位字节放前面,低位字节放后面。

例:一个数1234h(十六进制),如果是big-endian,则存放格式:1234h,从左开始是第0个字节。

如果是little-endian格式,则存放:4321h,从左开始是第0个字节。

big-endian通常用在Mac机中。little-endian通常在intel的pc中。

keep-alive: <len=0000>
keep-alive(保持连接) 消息内容=0, 所以内容长度设为0.这个消息既然没有ID,也没有内容。如果peer没有收到任何消息,peer可能关闭连接,所以这样发一个0000过去保持连接(说明你还活着)。通常这个消息间隔2分钟一次。

choke :<len=0001><id=0>
choke(拒绝或阻塞) 定长为1,没有内容。

unchoke :<len=0001><id=1>
unchoke(解除拒绝和阻塞) 消息是定长1,没有内容。

interested :<len=0001><id=2>
interested(感兴趣的) 消息为定长1,无内容。

not interested :<len=0001><id=3>
not interested(不感兴趣) 消息为定长1,无内容。

前面这几个消息都是设状态。 

have :<len=0005><id=4><piece index>
have(有片) 消息定长. 内容是一个piece索引序号,从0开始,表示已经正确下载并且经过哈希校验的片。

重要提示:这是一个严格定义。因为peer极有可能不去下载他们已经有的piece,一个peer可能选择不通告它有了哪个piece。至少可能会导致这个消息减少50%,转化为协议总消耗减少25-35%。

一个恶意的peer可能会选择宣传它已经有了从没下载的peer,也就是宣称自己有数据,但是实际上是假的。这是一个坏主意。 

bitfield :<len=0001+X><id=5><bitfield>
bitfield(片的状态) message 这个消息仅仅在握手完成后立刻发送,必须在其他消息发送之前。这是一个可选消息,如果client没有piece,则不用发。

这个消息长度可变最后bitfield的内容是一个X. 内容表示了已经被正确下载的片。第一个字节的最高位相当于piece序号0,依次下去,如果有效的piece则设1,如无效则设0. 如果结尾有多余的位则设0.

如果bitfield长度错误则被认为是一个错误。如果client收到一个不正确的长度或结尾多余位有任何被设为1,client可以关闭这个连接。

request :<len=0013><id=6><index><begin>
<length>
request(请求block) 消息定长,用来请求一个块block。内容包括以下信息
index(索引): integer整型,用来标识piece序号,从0开始。
begin(开始): integer整型,这个piece的偏移量,即从这个piece哪一个字节开始下载,偏移量从0算起。
length(长度): integer整型,请求字节数。通常设为2^14 (16384) 字节. 可以用更小的值,但是通常不需要设更小,除非整个piece不是16384的整数倍,那么最后一block可能就是要更小。
读者将注意到block通常小于一个piece(piece通常>=2^18),如果请求一个大于16384字节的块,client可能关闭连接。

piece :<len=0009+X><id=7><index>
<begin><block>
piece(片) 消息是可变长的,X是block的长度。内容包括以下信息
index: integer整型,就是piece的序号,从0算起。
begin: integer整型,piece中的偏移量,从0算起,按字节算。
block: 块的数据,是piece中的一部分,根据请求发回的数据。
cancel :<len=0013><id=8><index><begin>
<length>
cancel(取消) 定长消息。用来取消块请求。内容与request(请求)消息是一样的。如果发过去的请求不需要了,就用cancel照样取消。

port :<len=0003><id=9><listen-port>
port(监听端口) 这个消息用于一些新版本实现了DHT(Distributed Hash Table分布式哈希表)的tracker。这个监听端口是peer的DHT结点进行监听。这个peer将支持本地路由表(如果支持DHT tracker)。

DHT:  Distributed Hash Table分布式哈希表,目前bt的DHT技术都是基于Kademlia(很遗憾,发现wiki上的条目被封了有英文的http: //en.wikipedia.org/wiki/Kademlia),是一种典型的无中央服务器模式,也是一种客户端充当服务器和路由的模式。这是一种 将公网真正连接起来的技术,它将每个下载结点同时作为tracker服务器和路由,不再需要中央服务器进行索引和信息传递,所有安装客户端的软件平等自由 地充当整个P2P网络中的结点。

 http://www.167bt.com/bbs/viewthread.php?tid=47120&fpage=1 这是引自bt精灵的一段话,可作参考。

Algorithms
Super Seeding(超级种子)
(这不是原来协议的一部分)

超级种子是一种新的种子规则,用于帮助torrent发起人限制带宽。减少上传数据。

当做种的client进入超级种子模式,它不是作为一个标准种子,但是装作为一个普通的无数据client。当client连接上来,它将告诉他们它收到 一个piece,一个从未发送的piece或者如果所有piece已经被发送(这是非常罕见的),这导致client仅仅下载这个piece。

当client已经下载完这个piece后,种子不通过它其他的piece,直到它已经看到这个piece发给其它至少一个client。不是这样,这个client不允许存取其他的piece,因此不浪费种子的带宽。

这个原理是必须保证每个piece都有一个以上的client被下载,并且逐个piece处理,保证做种者不会占用太多带宽。

这个方法的结果是更多的种子传播,因为当做种初期,必须要求有很多client来下载,大概效率上会超过标准种子的150-200%。

超级种子模式不是推荐的。因为违背了自由传播的思想,但是可以提高传播效率,因此仅建议用于初始种子服务器。

可以换个名字,叫"初始做种模式"或"释放者模式"。

Piece downloading strategy(piece下载策略)
client是可以随机选择下载的piece,没有顺序要求。

一个更好的策略是"珍稀优先"下载。client可以保留每个peer的初始bitfield(piece状态),然后根据have消息来更新这个状态。这样,client可以根据最后的频率来判断和决定下载哪个piece。

End Game(结束)
当一个下载几乎要完成的时候,最后少量block下得比较慢。要提升这个速度,client要发送所有需要的块请求给所有的peer。保证这个适当可怕的低效率,当一个block到达的时候,client就发送cancel给其他所有人。

结束算法还可以有很多种选择,需要多实践。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值