BTlinux C编程实战文档格式.docx
《BTlinux C编程实战文档格式.docx》由会员分享,可在线阅读,更多相关《BTlinux C编程实战文档格式.docx(15页珍藏版)》请在冰豆网上搜索。
![BTlinux C编程实战文档格式.docx](https://file1.bdocx.com/fileroot1/2023-2/1/62348e77-c7be-45ee-9d4b-d5e2834f5d2f/62348e77-c7be-45ee-9d4b-d5e2834f5d2f1.gif)
连接Tracker获取peer的IP和端口。
连接peer进行数据上传和下载。
对要发布的提供共享文件制作和生成种子文件。
2.种子文件结构
BT下载软件(linuxC编程实战)2011-10-2914:
43
28人阅读
B编码
种子文件和Tracker的返回信息都是经过B编码的。
B编码有4种类型:
字符串、整型、列表、字典。
字符串格式:
<
字符串的长度>
:
字符串>
。
如:
字符串spam,经过B编码为4:
spam
整型的编码格式:
i<
十进制的整型数>
e,即以i开头,以e作为终结符。
如整数3表示为i3e。
列表的编码格式:
l<
任何合法的类型>
e,如l4:
spam4:
eggse表示两个字符串,一个是spam,另一个是eggs。
字典的编码格式:
d<
关键字>
值>
e,其中关键字是一个经过B编码的字符串,值可以是任何合法的B编码类型,d和e之间可以
出现多个关键字和值对。
d4:
spaml3:
aaa3:
bbbee,表示:
该字典的关键字是spam,值是一个列表(以l开始,以e结束),列表中
有两个字符串aaa和bbb。
种子文件的结构
种子文件以.torrent为后缀名,种子文件事实上是一个B编码的字典,它含有以下关键字
info:
该关键字的值是一个字典,含有两种模式,"
singelfile"
和"
multiplefile"
,文件模式和多文件模式。
announce:
Tracker的URL.
announce-list:
可选,备用Tracker的URL.
creation-date:
可选,创建种子文件的时间。
comment:
可选,种子文件制作者的备注信息。
info是最重要的一个关键字,它的值是一个字典。
该字典包含的关键字为:
piecelength:
每个piece的长度,值是一个B编码的整型,该值通常为i262144e,即256K,也有可能为512K或128K.
pieces:
对应为一个字符串,存放的是各个piece的hash值,每个字符串的长度一定为20的倍数,因为每个piece的hash
值的长度为20字节。
private:
该值如果为1,则表明客户端必须通过连接Tracker来获取其他下载者,即peer的IP地址和端口号;
如果为0,则表明
客户端还可以通过其他方式来获取peer的IP地址和端口号,如DHT方式。
对于但文件模式的种子文件,info的值还含有的关键字为:
name:
共享文件的文件名,即要下载的文件的文件名。
length:
共享文件的长度,以字节为单位。
md5sum:
可选,BT协议中无用。
对于多文件模式的种子文件,info还含有如下关键字:
存放所有共享文件的文件夹名。
files:
它的值是一个列表,列表中含有多个字典,每个共享文件为一个字典,该字典含有三个关键字。
length:
md5sum:
可选,无用
path:
存放的共享文件的路径和文件名。
3.与Tracker交互及peer之间的通信
BT下载软件(linuxC编程实战)2011-10-2917:
07
67人阅读
与Tracker交互主要有两个目的:
一是将字节的下载进度告知给Tracker以便Tracker进行一些相关的统计;
二是获取
当前下载同一个共享文件的peer的IP地址和端口号。
客户端使用HTTP协议与Tracker进行通信。
Tracker通过HttpGet方法获取请求,如htttp:
//myBT.net/announce
?
param1=value1&
param2=value2。
客户端发往Tracker的Get请求中,包含的参数为:
info_hash:
与种子文件中info关键字对应的值,通过Shal算法计算其hash值,该值就是info_hash参数对应的值。
peer_id:
每个客户端在下载文件前以随机的方式生成的20字节的标示符,用于标识自己,它的长度也是固定不变的。
port:
监听端口号,用于接收其他peer的连接请求。
uploaded:
当前总的上传量,以字节为单位。
downloaded:
当前总的下载量,以字节为单位。
left:
还剩余多少字节需要下载,以字节为单位。
compact:
该参数指示服务器以何种方式返回peer,该值为1时,每个peer占6个字节,前4个字节为peer的IP地址,
后两个为peer的端口号。
event:
它的值为started,completed,stopped其中之一,客户端第一次与Tracker进行通信时,该值为started,下载
完成时,该值为completed;
客户端即将关闭时,该值为stopped。
ip:
可选,将客户端的IP地址告知给Tracker。
numwant:
可选,希望Tracker返回多少个peer的IP地址和端口号。
key:
可选,值为一个随机数,用于进一步标识客户端。
trackerid:
可选,一般不用。
Tracker服务器的返回信息是一个经过B编码的字典:
failurereason:
指明Get请求失败的原因,如果返回信息中含有这个关键字,就不会在包含其他任何关键字。
warngingmessage:
一个可以读到的警告字符串。
interval:
指明客户端在下一次连接Tracker前所需等待的时间,以秒为单位
mininterval:
指明客户端在下一次连接Tracker前所需等待的最少时间,以秒为单位
trackerid:
指明Tracker的ID。
complete:
一个整数,指明当前有多少个peer已经完成了整个共享文件的下载
incomplete:
一个整数,指明当前有多少个peer还没有完成共享文件的下载。
peers:
返回各个peer的IP和端口号,他的值是一个字符串,首先是第一个peer的IP地址,然后是其端口号,接着是第二个peer的IP
地址,然后是其端口号。
peer之间的通信协议
peer之间的通信协议是一个基于TCP协议的应用层协议
客户端与peer建立TCP连接后,客户端必须维持的几个状态变量:
am_chocking:
该值若为1,表明客户端将远程peer阻塞。
此时如果peer发送数据请求给客户端,客户端将不会理会。
即一旦
将peer阻塞,peer就无法从客户端下载到数据。
该值若为0,则刚好相反,即peer未被阻塞,允许从客户端下载数据。
am_interested:
为1,表明客户端对远程的peer感兴趣,当peer拥有某个piece,而客户端没有,则客户端对peer感兴趣。
该值若为0,则相反。
peer_chocking:
为1,表明peer见啊ing客户端阻塞,此时,客户端无法从peer处下载到数据。
若为0,表明客户端可以向peer发送
数据请求,客户端将进行相应。
peer——interested:
为1,peer对客户端感兴趣,即客户端拥有某个piece,而peer没有。
为0,表明peer客户端不感兴趣。
4.关键算法及策略
BT下载软件(linuxC编程实战)2011-10-3114:
08
29人阅读
1.流水线作业:
当客户端向peer发送数据请求时(即发送request消息),一次请求多个slice(即一个数据包发送多个request消息请求多个slice)。
假如客户端一次
只发送一个slice请求,则peer给客户端发送完一个slice的数据后进入等待,等待客户端发送新的数据请求。
如果一次发送多个slice请求,则peer
发送完一个slice后接着发送下一个slice,从而避免了等待,提高数据传输的效率。
2.片段选择算法:
片段选择的第一个策略:
最少优先。
即某个piece在所有peer中的拥有率最低,则优先下载该piece。
第二个策略:
第三个策略:
随即选择第一个要下载的piece。
开始下载时,不能采用最少优先策略。
因为如果piece的拥有率很低,则下载到这个piece就相对较难
如果随即选择一个piece,那么更容易下载到该piece,一旦客户端下载到一个完整的piece,就可以提供给其他peer下载,而由于客户端向
其他peer上传数据,会倒在其他peer对客户端解除阻塞,从而有利于在起始阶段获得较高的下载速度。
当在下载到一些piece后,客户端
应采用最少优先策略来下载数据,这虽然会导致客户端的下载速度在短期内有所下降,但随后下载速度会有较大提高。
第四个策略:
最后阶段模式。
有时,从一个传输速度很慢的peer处下载一个piece会花费很长时间,在下载的过程中不是什么大问题,但在下载接近
完成时,如果发生这种情况,会导致客户端迟迟不能下载完成。
为了解决这个问题,在最后阶段,客户端向所有peer发送对这个piece
的某些slice请求,一旦收到某个peer发来的slice,则向其他peer发送cancel消息,只从当前这个peer处下载。
3.阻塞算法:
peer从它可以连接的peer下载文件,并根据对方提供的下载速度给予同等的上传回报,对于合作者,提供上传服务,对于不合作的,就
阻塞对方。
阻塞是一种临时拒绝上传的策略,虽然上传停止了,但是下载仍然继续。
在解除阻塞时,连接并不需要重新建立。
因为
阻塞过程中只是传输piece消息,其他消息,如have消息等仍可以传输。
5.系统模块设计
BT下载软件(linuxC编程实战)2011-10-3115:
01
33人阅读
评论
(1)
1.种子解析:
负责解析种子文件,从中获取Tracker服务器的地址,待下载的文件名和长度,piece长度,各个piece的hash值。
2.连接Tracker:
根据HTTP协议构造获取peer地址的请求,与Tracker建立连接,解析Tracker的回应消息,从而获取各个peer的IP地址和端口号。
3.与peer交换数据:
根据peer的IP地址和端口号连接peer,从peer处下载数据并将已下载的数据上传给peer。
4.出错处理:
定义整个系统可能出现的错误类型,并对错误进行处理。
5.运行日志:
记录程序运行的日志,并保存到文件中以备查看和分析。
与peer交换数据是本系统的核心和主要构成部分,划分为如下几个子模块
1.peer管理:
系统为每个已建立TCP连接的peer构造一个peer结构体。
本模块负责管理peer链表,添加和删除peer结点。
2.消息处理:
peer与peer之间以发送和接受消息的方式进行通信。
本模块负责根据当前的状态生成并发送消息,接受并处理消息。
其中对下载和
上传数据最重要的是request消息和piece消息。
request消息向peer发送数据请求,指明请求的是哪个piece的哪个slice。
peer接收
到request消息后根据当前的状态,决定是否发送数据给对方。
如果允许发送,则构造piece消息,数据被封装在该消息中。
每当下载完
一个正确的piece时,就像所有peer发送have消息通告已经获得该piece,其他peer如果没有该piece就可以向peer发送数据请求,每次
请求都是以slice为单位。
3.缓冲管理:
将下载到的数据先缓冲起来,等到下载到一定量的数据后在集中写入硬盘。
peer请求一个slice的数据时,先将该slice所在的整个piece
读入到缓冲区中,下载peer在请求该piece的其他slice时,只需在缓冲区获取,避免了频繁读写硬盘。
4.位图管理:
客户端与peer建立了连接并进行握手后,即发送位图给peer告知已下载到哪些piece,同时也接收对方的位图并将其保存在peer结构体。
没下载到一个piece就更新自己的位图,并发送have消息给所有已建立连接的peer。
每当接收到peer发来的have消息就更新该peer的位图。
5.策略管理:
主要计算各个peer的下载和上传速度,根据下载速度选择并阻塞peer,采用随机算法选择优化非阻塞peer,以及实现片段选择策略。
6.信号处理:
在运行过程中,程序可能接收到一些信号。
Peer管理模块的设计和实现
BT下载软件(linuxC编程实战)2011-11-0417:
05
系统为每个与之建立TCP连接的Peer构造一个Peer结构体。
Peer管理模块负责管理由各个Peer结点构成的Peer链表,主要工作是创建结点,
添加结点到Peer链表,从Peer链表删除结点等。
Peer结构体中定义了7种状态,分别是:
1.Halfshaked(半握手状态):
已经发送握手消息但未收到对方的握手消息,或已经接受到对方的握手消息,但已方未发送握手消息。
BT协议各种消息
BT下载软件(linuxC编程实战)2011-11-0515:
35
71人阅读
1.客户端与一个peer建立TCP连接后,首先向peer发送握手消息,peer收到握手消息后回应一个握手消息。
l
握手消息是一个长度固定为68字节的消息。
消息的格式如下:
pstrlen>
pstr>
reserved>
info_hash>
peer_id>
消息格式中一些参数的含义如表13-9所示。
表13-9
握手消息
参
数
含
义
pstrlen
pstr的长度,该值固定为19
pstr
BitTorrent协议的关键字,即“BitTorrentprotocol”
reserved
占8字节,用于扩展BT协议,一般这8字节都设置为0。
有些BT软件对BT协议进行了某些扩展,因此可能看到有些peer发来的握手消息这8个字节不全为0,不过不必理会,这不会影响正常的通信
info_hash
与发往Tracker的GET请求中的info_hash为同一个值,长度固定为20字节
peer_id与发往Tracker的GET请求中的peer_id为同一个值,长度固定为20字节。
一般从peer_id可以识别出BT软件的类型,例如,某peer发来的握手消息中peer_id的前8个字节为“-AZ2060-”,则可以断定对方使用的是Azureus;
若为“-BCxxxx-”,x为数字,则对方使用的是BitComet。
对于除握手消息之外的其他所有消息,其一般的格式为:
lengthprefix>
messageID>
payload>
lengthprefix(长度前缀)占4个字节,指明messageID和payload的长度和。
messageID(消息编号)占一字节,是一个10进制的整数,指明消息的编号。
payload(负载),长度未定,是消息的内容。
2.keep_alive消息:
len=0000>
keep_alive消息的长度固定,为4字节,它没有消息编号和负载。
如果一段时间内客户端与peer没有交换任何消息,则与这个peer的连接将被关闭。
keep_alive消息用于维持这个连接,通常如果2分钟内没有向peer发送任何消息,则发送一个keep_alive消息。
3.choke消息:
len=0001>
id=0>
choke消息的长度固定,为5字节,消息长度占4个字节,消息编号占1个字节,没有负载。
该消息的功能是,发出该消息的peer将接收该消息的peer阻塞,暂时不允许其下载自己的数据。
4.unchoke消息:
id=1>
unchoke消息的长度固定,为5字节,消息长度占4个字节,消息编号占1个字节,没有负载。
客户端每隔一定的时间,通常为10秒,计算一次各个peer的下载速度,如果某peer被解除阻塞,则发送unchoke消息。
如果某个peer原先是解除阻塞的,而此次被阻塞,则发送choke消息。
5.interested消息:
id=2>
interested消息的长度固定,为5字节,消息长度占4个字节,消息编号占1个字节,没有负载。
当客户端收到某peer的have消息时,如果发现peer拥有了客户端没有的piece,则发送interested消息告知该peer,客户端对它感兴趣。
6.notinterested消息:
id=3>
notinterested消息的长度固定,为5字节,消息长度占4个字节,消息编号占1个字节,没有负载。
当客户端下载了某个piece,如果发现客户端拥有了这个piece后,某个peer拥有的所有piece,客户端都拥有,则发送notinterested消息给该peer。
7.have消息:
len=0005>
id=4>
pieceindex>
have消息的长度固定,为9字节,消息长度占4个字节,消息编号占1个字节,负载为4个字节。
负载为一个整数,指明下标为index的piece,peer已经拥有。
每当客户端下载了一个piece,即将该piece的下标作为have消息的负载构造have消息,并把该消息发送给所有与客户端建立连接的peer。
8.have消息:
9.bitfield消息:
len=0001+X>
id=5>
bitfield>
bitfield消息的长度不固定,其中X是bitfield(即位图)的长度。
当客户端与peer交换握手消息之后,就交换位图。
位图中,每个piece占一位,若该位的值为1,则表明已经拥有该piece;
为0则表明该piece尚未下载。
具体而言,假定某共享文件共拥有801个piece,则位图为101个字节,位图的第一个字节的最高位指明第一个piece是否拥有,位图的第一个字节的第二高位指明第二个piece是否拥有,依此类推。
对于第801个piece,需要单独一个字节,该字节的最高位指明第801个piece是否已被下载,其余的7位放弃不予使用。
10.request消息:
len=0013>
id=6>
index>
begin>
length>
request消息的长度固定,为17个字节,index是piece的索引,begin是piece内的偏移,length是请求peer发送的数据的长度。
当客户端收到某个peer发来的unchoke消息后,即构造request消息,向该peer发送数据请求。
前面提到,peer之间交换数据是以slice(长度为16KB的块)为单位的,因此request消息中length的值一般为16K。
对于一个256KB的piece,客户端分16次下载,每次下载一个16K的slice。
11.piece消息:
len=0009+X>
id=7>
block>
piece消息是另外一个长度不固定的消息,长度前缀中的9是id、index、begin的长度总和,index和begin固定为4字节,X为block的长度,一般为16K。
因此对于piece消息,长度前缀加上id通常为0000400907。
当客户端收到某个peer的request消息后,如果判定当前未将该peer阻塞,且peer请求的slice,客户端已经下载,则发送piece消息将文件数据上传给该peer。
12.cancel消息:
id<
=8>
cancel消息的长度固定,为17个字节,len、index、begin、length都占4字节。