Linux下BT客户端的设计

时间:2022-08-12 06:50:58

Linux下BT客户端的设计

摘 要:设计一个linux下的BitTorent客户端,具体的实现分为五个大的模块:B编码分析模块,BitTorrent种子分析模块,BitTorrent客户端和Tracker服务器通信模块,BitTorrent客户端和BitTorrent客户端间的通信模块(peer to peer),运行日志模块,详细说明了模块的架构。

关键词:BitTorrent(bt);内容分发系统

中图分类号:TP

文献标识码:A

文章编号:1672-3198(2010)12-0295-03

1 引言

BitTorrent(简称BT)是一个内容分发协议,每个下载者在下载的同时不断向其他下载者上传自己已下载的数据。它的特点是下载的人越多下载的速度越快,其原因在于每个下载者将已下载的数据提供给其他下载者下载,它充分利用了用户的上载带宽。BT已经发展成为一种主要的互联网应用。本文尝试在Linux下设计一个轻量级的BT客户端软件,以快速文件传输为主要目的。

2 系统模块功能结构分析

根据BitTorrent协议,文件者会根据要的文件生成提供一个.torrent文件,即种子文件。.torrent文件本质上是文本文件,包含Tracker信息和文件信息两部分。Tracker信息主要是BT下载中需要用到的Tracker服务器的地址和针对Tracker服务器的设置,文件信息是根据对目标文件的计算生成的。它的主要原理是需要把提供下载的文件虚拟分成大小相等的块,块大小必须为2k的整数次方,并把每个块的索引信息和Hash验证码写入.torrent文件中,所以,.torrent文件就是被下载文件的“索引”。

下载时,BT客户端首先解析.torrent文件得到Tracker地址,然后连接Tracker服务器。Tracker服务器回应下载者的请求,提供下载者其他下载者(包括者)的IP。下载者再连接其他下载者,根据.torrent文件,两者分别告知对方自己已经有的块,然后交换对方所没有的数据。此时不需要其他服务器参与。

下载者每得到一个块,需要算出下载块的Hash验证码与.torrent文件中的对比,如果一样则说明块正确,不一样则需要重新下载这个块。这种规定是为了解决下载内容准确性的问题。

由此可见,在BT客户端设计中,最主要的部分是:

(1)对种子文件即.torrent文件的内容的解析,以获知Tracker地址和下载文件信息;

(2)与解析得来的Tracker服务器联系,获取其他下载者信息;

(3)与其他下载者互通有无。

其中,“与其他下载者交换数据”的部分又是最为重要的一环,它包含要处理的事务是最多的。除了这三个最主要部分外,还有需要的其他一些功能,比如对程序运行过程中出现的错误怎样处理,程序运行情况的记录等等。

根据对软件的总体分析,整个模块结构如图1所示。

图1 系统模块结构图

各个模块的功能如下。

(1)种子解析:主要工作包括对元信息文件的解码;根据本地数据文件的信息进行bencoding编码,制作元信息文件。

(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链表,添加和删除peer结点。

(2)消息处理:peer与peer之间以发送和接收消息的方式进行通信。本模块负责根据当前的状态生成并发送消息,接收并处理消息。

(3)缓冲管理:如果下载完一个piece就立即写入硬盘,这样会导致频繁读写硬盘,既影响速度,又不利于保护硬盘。为了解决这个问题,几乎所有的BT软件都在程序中增加了一个缓冲管理模块。将下载到的数据先缓存起来,等到下载到一定量的数据后再集中写入硬盘。本模块负责维护一个缓冲区,将下载到的数据保存在缓冲区中,并在适当时刻写入硬盘的文件中。

(4)位图管理:BT协议采用位图指明当前哪些piece已经下载,哪些piece还没有下载。本模块负责管理位图,对位图的操作主要是创建位图,设置和获取位图某一位的值,保存位图等。

(5)策略管理:BT协议的设计者为了保证整体性能而制定了许多策略,BT软件开发者一般都使用这些策略来保证程序的性能。本部分负责策略的管理,主要是计算各个peer的下载和上传速度,根据下载速度选择非阻塞peer,采用随机算法选择优化非阻塞peer,以及实现片断选择策略。

(6)信号处理:在运行过程中,程序可能会接收到一些信号,如SIGINT、SIGTERM,这些信号的默认动作是立即终止程序。这并不是所期望的。在程序终止前需要作一些处理,如释放动态申请的内存、关闭文件描述符、关闭套接字。

3 系统主要模块设计

3.1 种子解析模块的设计

此模块主要对元信息文件进行Bencoding解码。当从Web服务器上下载种子文件后,BT客户端就可以通过分析种子文件然后去访问Tracker服务器,Tracker服务器将随机选择部分参与下载的节点(一般随机选择50个节点)作为此请求节点的合作节点,并将这些节点的信息发送给请求节点,新加入节点将同这些合作节点建立连接后便下载或上传文件片段的编码块,并将已解码的文件片段写入磁盘文件。当BT客户端作为种子节点时,它需要根据本地数据文件的信息制作元信息文件,然后到Web服务器上,等待其他节点的请求连接,并从本地数据文件中读取相应的文件片段,然后将编码之后的编码块上传给相应的合作节点。因此,BT客户端在其下载或上传过程中,一直需要对元信息文件进行操作。在BT客户端获得.torrent种子文件后做的第一件事就是对此种子文件进行解析,主要任务有:

(1)判断.torrent文件是否有效;

(2)得到如下的重要信息:tracker服务器列表、文件列表、分块尺寸、分块个数、分块sha1的数组;

(3)其他的一些次要信息如者,日期,注释等;

(4)计算infohash。

3.2 位图管理模块的设计

位图指明当前哪些piece已经下载,哪些piece还没有下载。每个piece占一位,值为0表示该piece还未下载到,为1则表明已经下载到该piece。客户端与peer建立了连接并进行握手之后,即发送位图给peer告知已下载到哪些piece,同时也接收对方的位图并将其保存在peer结构体中。每下载到一个piece就更新自己的位图,并发送have消息给所有已建立连接的peer。每当接收到peer发来的have消息就更新该peer的位图。

BT客户端在进行下载或上传之前,首先把一个文件划分为若干个固定长度的文件片段(piece),再把一个文件片段划分为若干个固定长度的文件块(Block),piece位图中的每一个比特代表了相应的文件片段的下载状态,初始化时所有比特位为0,每当BT客户端下载了一个此文件片段的线性无关的编码块后,将piece位图中的相应比特位增1。Piece位图处理子模块将目标文件的piece位图抽象成一个EncodeField类,类的成员函数主要负责为piece位图开辟一块内存区域,更新piece位图中相应位的值,检查是否已完成目标文件的下载,将piece位图写入磁盘文件等等。

3.3 Peer管理模块的设计

Peer管理模块负责管理由各个peer结点构成的peer链表,主要工作是创建结点,添加结点到peer链表,从peer链表中删除结点等。系统为每一个与之建立TCP连接的peer构造一个peer结构体。该结构体的主要成员有:peer的IP地址和端口号、与该peer进行通信的套接字、该peer的ID、当前所处的状态、发送缓冲区、接收缓冲区、数据请求队列、数据被请求队列、从该peer处已下载的数据量和向该peer上传的数据量、下载速度和上传速度。

Peer结构是整个程序最重要的数据结构,也是最复杂的数据结构。在这个模块中首先定义了7种状态。

Halfshaked(半握手状态)是指已发送握手消息但未收到对方的握手消息,或者已经接收到对方的握手消息,但己方未发送握手消息。处于Data状态时双方可以交换数据,此时peer结构体中的am_choking、am_interested、peer_choking、peer_interested 4个成员变量有效。

当am_interested = 1,peer_choking = 0时,也就是客户端对peer感兴趣,而且peer没有将客户端阻塞,此时可以发送数据请求,即发送request消息请求peer发送数据,peer接收到请求后发送piece消息,数据就被封装在piece消息中。

当peer_interested = 1,am_choking = 0时,也就是peer对客户端感兴趣,而且客户端没有将该peer阻塞,此时如果peer发送request消息请求数据,则应该构造并发送piece消息,其中数据被封装在piece消息中。

“发送unchoke消息”的时机是执行选择非阻塞peer算法时,选中该peer作为非阻塞peer或者选中该peer作为优化非阻塞peer。“发送choke消息”的时机类似。

“发送have消息,拥有了peer没有的piece”的含义是己方刚刚下载到一个piece,此时通过发送have消息告知所有peer客户端已拥有了某个piece,如果peer没有这个piece且原先peer对本客户端不感兴趣,则发送have消息后,该peer就对该客户端感兴趣了。

3.4 消息处理模块的设计

peer与peer之间以发送和接收消息的方式进行通信。本模块负责根据当前的状态生成并发送消息,接收并处理消息。BitTorrent协议共定义了12种消息,其中对下载和上传数据最重要的是request消息和piece消息。request消息向peer发送数据请求,指明请求的是哪个piece的哪个slice。Peer接收到request消息后根据当前的状态,决定是否发送数据给对方。如果允许发送,则构造piece消息,数据被封装在该消息中。每当下载完一个正确的piece时,就向所有peer发送have消息通告已获得该piece,其他peer如果没有该piece就可以向peer发送数据请求,每次请求都是以slice为单位。在消息处理模块中,定义了如下12种消息:握手消息、keep_alive消息、choke消息、unchoke消息、interested消息、uninterested消息、have消息、bitfield消息、request消息、piece消息、cancel消息、port消息。

本模块中的消息处理流程见图2所示。

图2 消息处理流程图

3.5 缓冲管理模块的设计

在缓冲管理模块的实现中,有个重要的数据结构:Cache链表。Cache链表的存在是为了提高磁盘性能,降低对磁盘的读写次数,缺省大小为16M(大小可调整)。当BT客户端从本地数据文件中读数据时,会在Cache链表中保存一个复本,如果近期需要上传同样的数据时,可以直接从Cache链表中读取数据,不需要再次读本地数据文件。若缓冲区中不存在所请求的数据,则读文件并把请求数据所在的piece预先读入到缓冲区中。同样,BT客户端下载了数据并已经正确解码后,会先将数据写入Cache链表中,当Cache链表容量饱和时才写入本地硬盘数据文件。除了管理缓冲区,本模块还负责创建待下载的文件,把下载到的piece写入文件。BT系统既支持单个文件的下载,同时也支持多个文件的下载。上传和下载文件时,Cache管理流程分别如图3所示。

图3 Cache管理流程

每个缓冲区结点的大小为16KB,默认生成1024个结点,总大小为16MB。缓冲区以一个piece(通常为256KB)为基本单位,也就是临近的16个结点为一组,这16个临近的结点要么全部被使用要么全部空闲。第1-16个结点存放一个piece,第17-32个结点存放一个piece,依此类推。为了方便处理,所有缓冲区在程序启动时统一申请,在程序结束时一起被释放。

3.6 策略管理模块的设计

计算从各个peer处下载数据的速度是一个棘手的问题。经过分析和对比,现在用的计算下载速度的方法是每10秒计算一次速度。统计最近10秒内从每个peer处下载的数据量,然后除以时间,得到最近这段时间的下载速度,并将下载速度最快的4个peer解除阻塞,允许它们从本客户端下载,除一个特殊的peer外其他peer将被阻塞。为了发现更快下载速度的peer,任何时刻保证存在一个优化非阻塞peer,将这个peer解除阻塞,而暂时不管从该peer处下载数据的速度,每隔30秒重新进行选择。在这30秒内,本客户端提供给该peer较快的下载速度,然后该peer将本客户端解除阻塞,这样就可以从该peer处下载数据,并在下次选择非阻塞peer时,该peer能成为4个非阻塞peer中的一个。

阻塞策略是BT中很重要的一个问题,其优劣直接影响到BT下载的速度。

3.7 连接Tracker模块的设计

连接Tracker模块的主要功能是:构造HTTP请求,请求Tracker服务器发送peer的IP地址和端口号;与Tracker建立连接;解析从Tracker返回的数据。Tracker返回的数据是经过B编码的,解析Tracker的回应和解析种子文件是类似的。根据本地数据文件的信息进行Bencoding编码,为制作元信息文件子模块提供编码功能。从数据类型的角度来看,此子模块主要是对整数、字符串、列表、字典四种数据类型进行编码和解码操作。其工作流程见图4所示。

图4 与Tracker的交互

3.8 与peer交换数据模块的设计

本模块由多个子模块构成,主要负责与已建立连接的peer交换数据。除此之外,还调用“连接Tracker”模块中定义的函数监视各个套接字,以及尝试与新的peer建立TCP连接。

Peer,抽象表示与BT客户端建立连接并通信的合作节点,每一个peer,代表着一个合作节点。Peer主要从下载数据的速率、上传数据的速率、BT客户端与合作节点连接的状态、合作节点的piece位图、通信错误次数等角度来描述客户端与合作节点之间的通信状态。

至此主要模块的设计分析完毕,接着就是代码实现。

参考文献

[1]吴圣杰.基于Linux限制BitTorrent流量的研究与设计[D].北京:北京化工大学,2007.

[2]李培峰,朱巧明.Linux下支持续传的多线程下载工具的设计与实现[J].计算机工程与应用,2004,(1).

[3]王枫,罗家融.Linux下多线程Socket通讯的研究与应用[J].计算机工程与应用,2004,(16).

[4]田荣华,卢显良,侯孟书,王晓斌.P2P分布式存储系统[J].计算机科学,2007,(6).

[5]郭辉,周敬利,余胜生.基于Linux的HTTP协议实现方案及性能改进的研究[J].计算机工程,2001,(11).

[6]冀志刚,王祥.用JAVA语言实现FTP客户端[J].唐山师范学院学报,2006,(5).

上一篇:机房管理谋略 下一篇:露天采矿测绘数字化应用探讨