zoukankan      html  css  js  c++  java
  • BT源代码学习心得(六):跟踪服务器(Tracker)的代码分析(初始化) 转自CSDN:gushenghua的专栏

    BT源代码学习心得(六):跟踪服务器(Tracker)的代码分析(初始化)

    发信人: wolfenstein (NeverSayNever), 个人文集
    标  题: BT源代码学习心得(六):跟踪服务器(Tracker)的代码分析(初始化)
    发信站: 水木社区 (Mon Aug  8 11:30:43 2005), 文集
    (本文包含HTML标记,终端模式下可能无法正确浏览)
        Tracker在BT中是一个很重要的部分。这个名词我注意到以前的文章中都是直接引用,
    没有翻译过来,想了一下,决定把它翻译成跟踪服务器。
        在BT下载中,种子文件表明了要下载的文件的信息和对它进行检查的消息摘要码,但是
    每个对等客户(peer,以后我把peer全部翻译成对等客户,以区别client)要获取其它对等客
    户的信息时,还是要和跟踪服务器联系的。跟踪服务器上面不保存任何和种子所代表的内容
    有关的文件,它只记录所有下载该种子的机器的IP地址,端口等信息,并在客户向它请求是
    返回一些这样的信息列表,具体的实际内容,由对等客户之间完成交互。
        跟踪服务器的代码实现在BitTorrent/track.py中,在bttrack.py中只是很简单得一行

        track(argv[1:])
        这样就把参数传到track.py的track函数。track函数本身也比较简单,处理参数和相关
    的配置文件,建立一个RawServer,然后用create_serversocket创建服务器套接字,然后开
    始服务。关于在BT中使用网络服务上次已经有很详细地介绍,这里不再重复。只是针对
    tracker函数的具体情况,分析一下运行到listen_forever后的情况,首先,建立了
    Tracker对象,打开了在某个端口(config['port'])侦听的网络服务,这个函数的处理对象
    是一个HTTPHandler。所以我们要分析程序的流程只需要先分析Tracker的初始化函数,看看
    它创建后都做了些什么,然后再看HTTPHandler实际分析它的网络协议。
        在Tracker对象的初始化函数中,首先还是对各种变量的初始化。然后要从一个状态文
    件中进行一些状态恢复,也就是恢复state变量。这个变量中的值很重要,我们可以需要从
    一些地方来得知它的结构,状态文件的读取和保存出得不到它的信息,因为这两处的实现方
    式就是bencode和bdecode,只能保证无论state的结构是什么都能合适得被保存和恢复,由
    此又看出bencode编码设计的巧妙。但是有一个函数对我们分析state的内部结构很有帮助,
    那就是statefiletemplate,这个函数检查state中的值是否合法,因此我们可以从这里得到
    state的一些结构信息。
        首先,state必须是一个字典类型的变量。然后检查每一项的值。如果发现一项关键字
    是'peers',那么它的值必须也是一个字典,这个字典是一个以种子文件的信息部分的消息
    摘要值为关键字的字典,由于sha摘要算法比较好得满足了摘要算法的要求,即不同的种子
    文件它们生成相同摘要的概率极小。而且由于这是由种子文件的内容生成的摘要值,因此即
    使把种子文件改名,还是可以识别出来是哪个种子文件。因此'peers'的值可以看成是为每
    一个种子文件记录的信息,那么为每个种子文件记录的是什么信息呢?这个信息又是一个字
    典,这次以每个对等客户的ID为关键字,每个对等客户在连接到跟踪服务器的时候都会为自
    己生成一个ID,这个ID怎么生成的以后看客户端的代码可以知道,现在我们知道的是,它的
    长度必须为20。这个字典的值,嗯,又是个字典,不过这个字典的意义就明显多啦,包括了
    IP是多少,端口是多少,还剩多少没有下载完。因此state的内容可以看成是这样的:{'
    peers':{},...},其中peers的结构是这样的:{hash1:{ID1:{'ip':xxx.xxx.xxx.xxx,'
    port':xxxx,left:XXXX},ID2:{'ip':yyy.yyy.yyy.yyy,'port':yyyy,left:YYYY},...},
    hash2:{...},...}。以上是state中'peers'这一项。'completed'这一项就相对结构简单了
    ,它记录的是每个种子文件的下载完成情况,它的结构是个字典,以每个种子的信息部分的
    消息摘要值为关键字,而对应的值就是一个整数,表示该种子文件已经有多少人完成了下载
    。接下来是'allowed'项,这项记录了该跟踪服务器所关注的所有的种子的信息,仍然以信
    息部分的消息摘要值为关键字,内容就是该种子文件的实际信息,从后面的分析(对
    BitTorrent/parsedir.py的分析)可以知道是哪些信息,另外由于之前对种子文件的内部结
    构我们已经比较清楚,所以也可以猜出部分。state中还有'allowed_dir_files'项,这一项
    也是记录文件信息的字典,但它是以每个文件的文件名为关键字(而不是消息摘要值),每个
    文件的项目是一个列表,结构如下:[(文件修改时间,文件大小),消息摘要值],就是说,这
    个以文件名为关键字的字典它的每一个值都是一个列表,这个列表有两个元素,第一个元素
    是一个二元组,内容是文件修改时间和文件大小,第二个元素是消息摘要值。最后,我们注
    意到statefiletemplate在处理'allowed'项和'allowed_dir_files'项时还有一些额外的检
    查代码,即所有在'allowed'项里面出现的元素,它的消息摘要值都必须在'
    allowed_dir_files'项中出现,且'allowed_dir_files'中所有的项中的值的消息摘要部分
    必须在'allowed'中出现,另外'allowed_dir_files'中不得出现重复的消息摘要值('
    allowed'项本身就以消息摘要值为关键字,而字典的关键字已经保证不会重复)。
        因此现在我们知道了state中的注意部分的结构。下面我们注意这两句:
        self.downloads    = self.state.setdefault('peers', {})
        self.completed    = self.state.setdefault('completed', {})
        这样就把state中的'peers'和'completed'的值传到了downloads和completed中,更重
    要的是,以后在跟踪服务器的运行过程中,如果'peers'和'completed'的值发生改变(那简
    直是一定的),state中的相应值也会发生变化,这样,保存dfile时,就可以及时更新
    state的值了。以后我们分析跟踪服务器运行过程的时候少不了和它们打交道,现在我们可
    以先记住,downloads保存了所有的下载的客户端的信息,completed保存所有的种子的下载
    完成情况的统计信息。
        下面的这个for循环根据配置文件处理NAT的问题,以及计算种子的个数。completed只
    是记录所有下载完成的客户的数目,而只有已经下载完成(left=0),但是还在downloads中
    出现(即下载完毕但是没有关闭客户端)的客户端才算是一个种子。这里我们可以很容易得看
    出,seedcount是一个以信息摘要为关键字,整型为值的统计种子数的一个字典。
        下面是一个计算的变量,times表示了每个种子(以信息摘要为关键字)中每个客户(以客
    户ID为关键字)的上次的有活动的时间。接下来增加了两个任务,每隔一段时间保存一下
    dfile,并且检查下载的客户端是否已经有很长时间没有反应的。
        接下来准备一个日志文件,并试图把标准输出重定向到这个日志文件中。
        最后要去寻找该跟踪服务器所关注的所有的种子,即parsedir,这个函数可以自己去看
    ,相信在知道了种子文件的编码格式和前面的状态中的项的要求后,不难分析。总得说来,
    这个函数做了以下事情,即寻找某个目录下所有的.torrent文件,把这些文件中的信息读取
    进来,并且排除错误,重复等等不合要求的,然后进行加工,输出符合要求的结果,储存在
    allowed和allowed_dir_files中,进而影响state。
        现在tracker对象已经建立起来,它已经有它要进行跟踪的所有种子的信息,并且准备
    好了维护所有连接进来的客户的列表,因此它可以正式开始提供跟踪服务了。下一次我们就
    可以看看tracker动起来的效果。
     
  • 相关阅读:
    UI- 基础控件零散知识点回归
    UI-定时器与动画使用总结
    IE浏览器url中带中文报错的问题;以及各种兼容以及浏览器问题总结
    java实现判断一个经纬度坐标是否在一个多边形内(经自己亲测)
    高德地图web端笔记;发送http请求的工具类
    高德地图JSapi
    shiro(三),使用第三方jdbcRealm连接数据库操作
    shiro(二)自定义realm,模拟数据库查询验证
    java安全框架shiro(一)
    解决celipse中mybatis使用的时候xml没有提示的问题
  • 原文地址:https://www.cnblogs.com/kokoliu/p/616912.html
Copyright © 2011-2022 走看看