peer之间的通信协议

5841阅读 2评论2012-01-18 liurhyme
分类:LINUX

peer之间的通信协议

 peer之间的通信协议又称为peer wire protocal,即peer连线协议,它是一个基于TCP协议的应用层协议。

 为了防止有的peer只下载不上传,BitTorrent协议建议,客户端只给那些向它提供最快下载速度的4peer上传数据。简单地说就是谁向我提供下载,我也提供数据供它下载;谁不提供数据给我下载,我的数据也不会上传给它。客户端每隔一定时间,比如10秒,重新计算从各个peer处下载数据的速度,将下载速度最快的4peer解除阻塞,允许这4peer从客户端下载数据,同时将其他peer阻塞。

 一个例外情况是,为了发现下载速度更快的peer,协议还建议,在任一时刻,客户端保持一个优化非阻塞peer,即无论该peer是否提供数据给客户端下载,客户端都允许该peer从客户端这里下载数据。由于客户端向peer上传数据,peer接着也允许客户端从peer处下载数据,并且下载速度超过4个非阻塞peer中的一个。客户端每隔一定的时间,如30秒,重新选择优化非阻塞peer


当客户端与peer建立TCP连接后,客户端必须维持的几个状态变量如下表所示。

 客户端必须维持的状态变量

状 态 变 量

                        含    义

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  = 1

am_interested  = 0

peer_chocking  = 1

peer_interested = 0

当客户端对peer感兴趣且peer未将客户端阻塞时,客户端可以从peer处下载数据。当peer对客户端感兴趣,且客户端未将peer阻塞时,客户端向peer上传数据。

除非另有说明,所有的整数型在本协议中被编码为4字节值(高位在前低位在后),包括在握手之后所有信息的长度前缀。

客户端与一个peer建立TCP连接后,首先向peer发送握手消息,peer收到握手消息后回应一个握手消息。

l 握手消息是一个长度固定为68字节的消息。消息的格式如下:

消息格式中一些参数的含义如下表所示。


握手消息

参    数

含    义

pstrlen

pstr的长度,该值固定为19

pstr

BitTorrent协议的关键字,即“BitTorrent protocol

reserved

8字节,用于扩展BT协议,一般这8字节都设置为0。有些BT软件对BT协议进行了某些扩展,因此可能看到有些peer发来的握手消息这8个字节不全为0,不过不必理会,这不会影响正常的通信

info_hash

与发往TrackerGET请求中的info_hash为同一个值,长度固定为20字节


peer_id与发往TrackerGET请求中的peer_id为同一个值,长度固定为20字节。一般从peer_id可以识别出BT软件的类型,例如,peer发来的握手消息中peer_id的前8个字节为-AZ2060-,则可以断定对方使用的是Azureus;若为-BCxxxx-”,x为数字,则对方使用的是BitComet


对于除握手消息之外的其他所有消息,其一般的格式为:


length prefix(长度前缀)占4个字节,指明message IDpayload的长度和。message ID(消息编号)占一字节,是一个10进制的整数,指明消息的编号。payload(负载),长度未定,是消息的内容。

l keep_alive消息

keep_alive消息的长度固定,为4字节,它没有消息编号和负载。如果一段时间内客户端与peer没有交换任何消息,则与这个peer的连接将被关闭。keep_alive消息用于维持这个连接,通常如果2分钟内没有向peer发送任何消息,则发送一个keep_alive消息

l choke消息

choke消息的长度固定,为5字节,消息长度占4个字节,消息编号占1个字节,没有负载。该消息的功能是发出该消息的peer将接收该消息的peer阻塞,暂时不允许其下载自己的数据。

l unchoke消息1>

unchoke消息的长度固定,为5字节,消息长度占4个字节,消息编号占1个字节,没有负载。客户端每隔一定的时间,通常为10秒,计算一次各个peer的下载速度,如果某peer被解除阻塞,则发送unchoke消息。如果某个peer原先是解除阻塞的,而此次被阻塞,则发送choke消息。

l interested消息

interested消息的长度固定,为5字节,消息长度占4个字节,消息编号占1个字节,没有负载。当客户端收到某peerhave消息时,如果发现peer拥有了客户端没有的piece,则发送interested消息告知该peer,客户端对它感兴趣。

l not interested消息

not interested消息的长度固定,为5字节,消息长度占4个字节,消息编号占1个字节,没有负载。当客户端下载了某个piece,如果发现客户端拥有了这个piece后,某个peer拥有的所有piece,客户端都拥有,则发送not interested消息给该peer

l have消息 

have消息的长度固定,为9字节,消息长度占4个字节,消息编号占1个字节,负载为4个字节。负载为一个整数,指明下标为indexpiecepeer已经拥有。每当客户端下载了一个piece,即将该piece的下标作为have消息的负载构造have消息,并把该消息发送给所有与客户端建立连接的peer

l bitfield消息

bitfield消息的长度不固定,其中Xbitfield(即位图)的长度。当客户端与peer交换握手消息之后,就交换位图。位图中,每个piece占一位,若该位的值为1,则表明已经拥有该piece;为0则表明该piece尚未下载。具体而言,假定某共享文件共拥有801piece,则位图为101个字节,位图的第一个字节的最高位指明第一个piece是否拥有,位图的第一个字节的第二高位指明第二个piece是否拥有,依此类推。对于第801piece,需要单独一个字节,该字节的最高位指明第801piece是否已被下载,其余的7位放弃不予使用。

l request消息

request消息的长度固定,为17个字节,indexpiece的索引,beginpiece内的偏移,length是请求peer发送的数据的长度。当客户端收到某个peer发来的unchoke消息后,即构造request消息,向该peer发送数据请求。前面提到,peer之间交换数据是以slice(长度为16KB的块)为单位的,因此request消息中length的值一般为16K。对于一个256KBpiece,客户端分16次下载,每次下载一个16Kslice

l piece消息

piece消息是另外一个长度不固定的消息,长度前缀中的9idindexbegin的长度总和,indexbegin固定为4字节,Xblock的长度,一般为16K。因此对于piece消息,长度前缀加上id通常为00 00 40 09 07。当客户端收到某个peerrequest消息后,如果判定当前未将该peer阻塞,且peer请求的slice,客户端已经下载,则发送piece消息将文件数据上传给该peer

l cancel消息:

cancel消息的长度固定,为17个字节,lenindexbeginlength都占4字节。它与request消息对应,作用刚好相反,用于取消对某个slice的数据请求。如果客户端发现,某个piece中的slice,客户端已经下载,而客户端又向其他peer发送了对该slice的请求,则向该peer发送cancel消息,以取消对该slice的请求。事实上,如果算法设计合理,基本不用发送cancel消息,只在某些特殊的情况下才需要发送cancel消息。

l port消息:

port消息的长度固定,为7字节,其中listen-port占两个字节。该消息只在支持DHT的客户端中才会使用,用于指明DHT监听的端口号,一般不必理会,收到该消息时,直接丢弃即可。

上一篇:Python list 操作
下一篇:关键算法和策略

文章评论