BT服务器源码分析

本文由春华秋实编辑,地址http://hi.baidu.com/3600/blog/item/ab02a50f5ccf08eaab64578d.html

*****************************************************************************

转自:jijian91和小z 的关于bnbt的源码分析,由于原文连载较多,就直接转了过来
原文地址
http://jijian91.com/blog/internet/software/bittorrent‘

BT服务器源码分析1:BT体系架构

因为要对一个以BT(bnbt)为核心的系统进行优化改进,上网搜了一下BT服务器和客户端的源码分析资料,所获很少(有价值只有信仰小马哥)。只好自己总结,希望能留下点有用的。

要分析和改进BT,先要了解BT的架构和先说说BT的架构。

BT角色

  • torrent发布服务器:用来发布.torrent文件
  • tracker服务器:每个bt客户端都要连上tracker获得其他peer,所以tracker是BT架构的中心、peer的信息交互中心
  • peer:BT客户端,下载兼上传者。针对某个bt文件(即1个.torrent文件所指向的文件或目录),还可以分为seed和lecher。注意,1个peer可能是某个bt文件的seed,同时是另1个bt文件的lecher。
    • seed:种子,即拥有该bt文件的全部内容的peer。
    • lecher:种子以外的peer.

BT的运行原理

按照时间顺序,依次发生的是

  1. 制作torrent文件
    指定要发布的文件或目录和tracker的URL,制作出.torrent文件。
    tracker的URL格式是http://<ip>:<port>/announce。.torrent文件中记载了 tracker信息、发布者信息、上载的文件的长度和hash等,但不包含发布者服务器的信息。制作torrent文件后,就不要删除或移动发布的文件 了,以免别人无法下载。
    使用bitcomet可以很方便地制作bt文件。
  2. 发布torrent文件
    将torrent文件发布给别人。现在有很多torrent发布服务器,比如btchina。其实,用什么方式发布torrent文件无关紧要,只是因为torrent发布服务器上聚集了大量bt信息,别人比较容易找,发布到论坛、网站、博客上或者发布到多个服务器上都没问题。
  3. 用户下载torrent文件。
  4. bt客户端根据torrent文件信息,访问tracker。注册自己,得到该bt文件的一组peer的ip和port列表。
  5. 根据列表,与各peer建立双向连接,开始下载/上传。
  6. 定期访问tracker,汇报本客户端的下载/上传情况,得到更多peer列表。知道下载完毕,成为seed。

tracker和DHT

在bt体系运转过程中,tracker处于中心,是”全局单点”,所有的peer都要在tracker上注册、得到其他peer,并周期性地访问tracker更新信息。所以,如果tracker出现故障,peer间无法沟通,bt崩溃。

为了解决这个隐患,也为了加速peer间相互发现,搞了个DHT网络,bitcomet和BitTorrent Beta 4.1.1都支持。也就是允许peer互相交换peer列表,这样,即使tracker垮了,bt客户端也能通过已有的peer连接不断得到其他peer。但目前,DHT只是个补充。

seed、lecher和超级种子(super seed)

制作torrent文件的客户端是第1个seed(原始种子)。其他peer开始都是lecher,下载完毕变成seed。全部peer中,seed的比例大则下载总速度快。

如果原始种子离开过早或其他peer在成为seed以后立刻离开,可能造成全部peer的数据都构不成完整文件,这个bt文件就是无法下载的废文件。所以,seed的培养是bt中的重要问题。

为解决种子问题,BTPLUS S-5.5搞了个超级种子(super seed)概念。即:

当一个客户端启用超级种子模式时,他将伪装成一个没有数据的普通客户端。当其他客户端连接时,超级种子模式将传输给他一个 从没被 传输出去的块,当所有文件块都被发出时,将意味着不需要你这个种子其他下载者就可以完成下载进程.这样将大大降低一个文件块被下载多次的几率并提高做种效 率。这个方法将提高做种效率通过两者间的高效率数据传输,从而降低多余的数据传送。并限制对贡献少的下载者 的数据传送。使用这个功能后只要上传105%的总大小就可以培养 出新种子.这比普通种子的效率高1.5 到 2倍。

但超级种子模式会极大地降低对外传输数据流量,一般只建议Torrent文件发布者(原始种子)使用。

解决peer成为seed以后立刻离开的问题,才能提高bt体系整体效果,但目前尚无好的办法。

bt服务器和客户端

bt服务器主要就是tracker。我们用的是开源的bnbt。这是后文分析和改进的重点。

bt客户端就复杂了。

一是实现很多,只要不违反bt协议,实现原理上可以完全不同。但实际上,大多数bt客户端都是在bittorrent的基础上改进的。所以后文主要分析bittoreent客户端源码。

二是bt客户端的代码比服务器复杂得多,这与一般的情况刚好相反。

三是用户可以使用任何客户端,不可能要求用户改用我们改进的客户端。所以优化改进只能以bt服务器为主。

bnbt是应用较广的开源BT服务器(BT tracker)。下面分析一下bnbt tracker的主要流程(注意:没有使用数据库):

bnbt源码全部是C++,程序起点是bnbt.cpp中的main函数。其中首先解析命令行参数,然后是与Windows服务相关的处理,最后调用bnbtmain函数。

bnbtmain函数也在bnbt.cpp中。主要解析配置文件、设置大量运营参数,然后创建CServer的实例gpServer,最后是在死循环中不断调用gpServer.Update().

CServer类是在server.cpp中定义的。

CServer构造函数的主要工作是绑定监听端口,实际是建立了一个server,最后创建了CTracker的实例m_pTracker.

CServer类的Update()函数主要功能是处理连接上来的BT客户端。如果客户端队列m_vecClients未满(缺省最大64),则为每个连接创建1个CClient实例,并将其压入m_vecClients尾部。然后,依次执行m_vecClients中各CClient对象的Update函数,并将返回值为true的对象释放掉。

CClient类是在client.cpp中定义的。其构造函数很简单,重点是Update()函数。Update()函数的功能是处理BT客户端的请求。具体说,从socket连接读取信息,按照HTTP协议进行了分析,转化成GET和POST请求调用CServerCTrackerserverResponseGET()和serverResponsePOST()函数处理,将处理返回的结果再返给BT客户端。

CTracker类是在tracker.cpp中定义的。

serverResponsePOST()中只处理POST方式的”/upload.html”的请求,即上载页面。

serverResponseGET()是重点,处理以下请求:

  • /或/index.html:主界面,显示BT文件和以下各网页的链接
  • /announce:处理BT客户端访问,并返回其他BT客户端的ip:port列表,是tracker的核心功能
  • /scrape:可以通过scrape协议读取可下载的bt文件信息
  • /stats.html:显示统计信息
  • /torrents/:torrents是默认的存放torrent文件的目录,可以在配置文件中设置存放到其他目录
  • /files/:显示可下载的bt文件
  • /robots.txt:定义搜索引擎访问规则的robots.txt
  • /login.html:用户登录界面
  • /signup.html:用户注册界面
  • /upload.html:GET方式的上载界面
  • /info.html:tracker基本信息,包括版本、当前时间、运转时间、文件数、用户数。
  • /admin.html:admin界面
  • /users.html:用户信息界面
  • /comments.html:对文件注释

通过上文的分析可以看出,bnbt(也就是tracker)实际是一个socket服务器,但模拟成web server。很有意思:)bnbt对外是100%的web server。所以,用java或php重新写一套bt服务器,运行在web server上是完全没有问题的。

/announce是bnbt实现的各http页面中最核心的,也是bt客户端唯一访问的页面。BT服务器与客户端之间是通过基于HTTP的bt协议进行通讯,在bnbt源码中由CTracker.serverResponseAnnounce()函数实现。下篇文章我们将专门谈论这个函数。

除了/announce以外,其他页面都是可选的,所以很多bnbt服务器只提供部分。有兴趣的话,可以参看这个德国服务器,功能提供得比较全。

由上篇bnbt tracker执行流程,我们知道bt tracker的核心是/announce。BT客户端与tracker之间的通讯以及tracker内部是如何处理的呢?

我们从BT客户端发起请求开始。BT协议的具体内容不多说,参见这里

BT客户端首先读torrent文件,例如:
d8:announce35:http://192.168.0.1:2222/announce10:created by13:BitComet/0.9213:creation datei1192120049e8:encoding3:GBK4:infod4:ed2k16:魖趸?[T,胕@驋8:filehash20: 廹 C<`鮾}瀽穤茕蛯]6:lengthi43e4:name11:AUTORUN.INF10:name.utf- 811:AUTORUN.INF12:piece lengthi32768e6:pieces20: 廹 C<`鮾}瀽穤茕蛯]ee

其中,”http://192.168.0.1:2222/announce”是tracker URL,”AUTORUN.INF”是文件名,中间的乱码是文件的hash值,其他信息还有片段(piece)的长度(32K)、片段数、创建的软件、时间等。

BT客户端据此向tracker发送GET请求,例如:
GET http://192.168.0.1:2222/announce?info_hash=w%3D%1E%FB%A2%09%8C%E5k%2A%9F%A03PQ%3E%12%2CMq&peer_id=-BC0092-%89v%5E%0A%8Cf%EB%90%B1%0D%EE%DE&port=14479&natmapped=1&localip=192.168.0.65&port_type=lan&uploaded=0&downloaded=0&left=0&numwant=200&compact=1&no_peer_id=1&key=31526&event=started HTTP/1.1

其中,主要是文件的hash值(info_hash)、希望返回的bt客户端数量(numwant),以及本客户端的信息(peer id、port、已上传下载字节数等)。

bnbt在tracker_announce.cppCTracker.serverResponseAnnounce()函数中处理这个请求,具体流程是:

  1. 调用tracker.cpp中的CTracker.Announce()函数,将该BT客户端添加到该BT文件对应的peer列表中。peer列表无数量上限。
  2. 确定返回的peer数量,在tracker设置和BT客户端要求中取数值小者。
  3. 如果cache列表(pCacheList)中的peer数小于返回的peer数量,则将peer列表全部加到cache中。否则,跳到5
  4. 将cache列表顺序随机打乱
  5. 从cache列表开头依次取peer,加入到返回列表中,然后从cache中删除。

serverResponseAnnounce的处理过程比我想象的简单得多,它只是尽可能保证返回peer数量,并未对peer进行任何选择。换言之,tracker并不考虑返回的是seed,还是lecher。实际上,tracker根本就没有记录哪个peer是seed。因为BT客户端之间是建立双向传输连接互相传输数据的,所以BT的作者显然是想通过无为而治来达到自然的上下载平衡。

但在某些特殊的场景中,达不到这种理想平衡。比如,大量peer集中下载1个新文件,seed很少,绝大多数是完全没有数据的空lecher。 seed就会被淹没在空lecher的海洋中。每个peer得到的都是一堆空lecher,都不能下载到任何数据。而seed反而因为只有很少的peer 连接过来而空闲,从而使整个BT下载体系陷入停顿的状态,如同一个果料果冻,少数果料被包裹分隔,发挥不出作用。所以,我叫它“果冻效应”。后面我们将重点讨论果冻效应及其解决。

BT服务器源码分析5:BT客户端

2007-10-24 16:11 +0800

要优化BT服务器,除了分析BT体系结构分析BT服务器源码,还需要简单了解一下BT客户端的动作。

BT架构很有意思,客户端比服务器复杂得多。现在有很多BT客户端,大多是在BitTorrent的基础上改造的,加上自己的优化,而且不开放源码。例如,国内最常见的BitComet就是如此。BitTorrent不甘于为别人做嫁衣,最近宣布停止开放源码。BitTorrent公开源码的最后一个版本是5.0.9,可以在这里下载。

BitTorrent客户端是用python写的!对不熟悉python语言的人来说(我就是),看得晕头晕脑。最后,我参考了小马哥的分析,做了个简单归纳。好在目标只是大致了解,不用仔细研究。

BitTorrent客户端主要完成以下工作:

  1. 与 tracker通讯;
  2. 与其他peer建立对等连接;
  3. 启用片断选择算法,通过对等连接从其他peer下载所需要的片断;
  4. 将下载的片断写入磁盘;
  5. 为其他peer上传指定提供片断;
  6. 启用阻塞算法,阻塞某些peer的上传请求;

其中,1在前面已经分析过了。4不是我们关心的重点。

BT客户端从tracker得到peer列表后,就要主动与这些peer建立连接,同时也接受其他peer的连接请求。这就是2的具体内容。BT客户端间建立的是对等连接,由哪一方主动发起并不重要。一旦建立,就可以双向传输文件。支持DHT网络的,还可以传输peer列表。

建立连接的2个BT客户端中,至少有一方是公网IP或两方在同一个局域网内。如果一方是公网IP,另一方在局域网内,则只能是局域网内的向公网的发 出连接请求。一个BT体系下,必须存在一定量的公网用户,否则就是产生相互无法连接的问题。国内的现实情况是,多数公司、网吧和教育网都是局域网用户,所 以局域网用户比例偏高。拨号上网、ISDN、ADSL用户使用的是动态公网IP,所以近年来的ADSL普及对此有缓解作用。要注意的是,公网和局域网用户 只是在建立连接的时候作用不同,在连接建立后传送文件时是没有区别的。

片断选择算法相当复杂,目的是挑选“最全局价值最大”的片段进行下来。阻塞算法也是很复杂的,用于调整上下载比例,鼓励用户多提供上载作贡献,惩罚投机者。但对于BT体系整体优化作用不大,可以暂时忽略。

原文地址:https://www.cnblogs.com/bo083/p/2152787.html