• BT源代码学习心得(十四):客户端源代码分析(对等客户连接中的阻塞管理) 转自CSDN:gushenghua的专栏


    发信人: wolfenstein (NeverSayNever), 个人文集
    标  题: BT源代码学习心得(十四):客户端源代码分析(对等客户连接中的阻塞管理)
    发信站: 水木社区 (Wed Aug 17 17:56:50 2005), 文集
    (本文包含HTML标记,终端模式下可能无法正确浏览)
        从上一次我们的分析可以看出当对等客户建立连接后,通过握手协议交换信息,这样对
    于每个连接都有一个Connection对象,然后有一个SingleDownload和Upload与其对应。这一
    次将从握手协议完成后继续分析,然后介绍Choker,阻塞策略控制器的工作原理。
        SingleDownload在初始化时没有做什么特殊的操作,仅仅是创建了一个BadDataGuard对
    象和它对应。这个对象是用来统计坏数据的信息,以便确定坏的对等客户的。而Upload对象
    在创建的时候,如果自己已经有部分下载数据,就把自己的块拥有情况发送出去
    (send_bitfield)。现在就可以来看send_bitfield,我们可以看到在Connection中定义了不
    少send_xxx函数用来发送某种消息,并且在Connection对象定义之前,定义了那些消息的类
    型的对应的常数项。另外这些send_xxx函数大都调用了_send_message,它的作用就是在要
    发送的消息前面添加上它的长度(4个字节),然后发送出去,如果有必要,则放入队列中稍
    后发送。这样,每一次_got_message得到的就是消息的内容了。
        现在来看_got_message,它直接取第一个字节就行了,这就是消息的类型。以后我们可
    以再检查其它类型的消息,现在我们直接看elif t == BITFIELD这部分,得到对方的块拥有
    状况比特数组后,让自己的download对象记录下来,即调用
    SingleDownload.got_have_bitfield()。这个函数首先检查自己是否下载完成,然后检查对
    方的比特数组中"假"值的个数,如果自己下载完成了且对方的比特数组中"假"值为0,则说
    明对方也下载完成了,而两个都在做种的对等客户之间的连接是没有意义的,可以关闭它。
    然后self.have = have这一句记录下对方的块拥有情况。所以前面提到StorageWrapper保存
    自己的块拥有状况,而对应于每个Connection对象的SingleDownload对象中则保留了对方的
    块拥有状况。然后让PiecePicker记录下别人有一块(got_have,complete记录的是自己有一
    块,在_SingleTorrent的代码中可以看到)。下面的这个endgame则是一种策略模式,即表示
    进入收尾阶段,它检查自己所有的网络请求all_requests(后面还会分析到它),如果对方有
    某一块(再次注意,这里self.have[piece]是对方有第piece块,而不是自己),那么发送一
    条消息,send_interested()。表示说我对你(所拥有的内容)感兴趣。而如果没有进入收尾
    阶段,则只是检查自己有那块没有而对方有,如果有的话,则send_interested()。注意
    send_interested()调用一次,对方知道这个意思就行了。
        看Connection._got_message中得到这个消息后怎么处理。是
    self.upload.got_interested()。这个函数中维持自己的interested变量为真值,然后通知
    choker这件事情,choker.interested则选择是否要进行一次_rechoke()。
        现在应该注意到choked和interested这两个变量,这两个变量的值的意义分别是是否阻
    塞和是否感兴趣,它们对下载起到直接开关的作用。在每个SingleDownload和Upload对象中
    都有这两个变量。在初始化时,choked都为真而interested都为假,这样就不会有实际的内
    容(即种子文件的共享资源)在流通,而要有实际的内容流通必须这两个变量的值和它们初始
    化时的值刚好相反才行,也就是说,只有当一方对另外一方感兴趣,而对方又没有拒绝你
    (choked=false)的时候,你们之间在这个方向才可能会存在实际的下载流量。另外这两个变
    量在网络连接的每个方向都是保持一致的,即Upload中的这两个变量和连接另外一头的
    SingleDownload中的这两个变量保持一致,如果有某个变量发生变化,要发送消息给对方,
    让对方能继续保持一致。注意这里的保持一致指的是网络连接的两头,而不是本地的
    Connection对象对应的SingleDownload和Upload,即本地的Connection的SingleDownload和
    对等客户的Upload保持一致,而本地的Connection的Upload和对等客户的SingleDownload保
    持一致,而在同一个连接中,下载和上传的两个方向有可能不一致,即一个方向阻塞了,另
    一个方向还在下载。
        前面已经注意到,interested这个变量的改变很容易,只要发现对方有自己没有的块,
    就会发送这条消息,而choked这个变量的控制就有一定的策略了。Choker就控制所有的连接
    (_SingleTorrent级别)的阻塞。它在初始化时即保证_round_robin每十秒种执行一次,而每
    次有连接进入时,用connection_made来进行登记,Choker中维护了所有连接的列表,且这
    个列表是故意打乱顺序的。在BT的控制策略中,我们还可以多次看到随机打乱顺序的情况发
    生,因为有时随机数就是最好的策略。在_round_robin中,首先检查是否已经完成,如果完
    成则调用_rechoke_seed(),按照自己已经开始做种的情况进行处理。而计算count%3的余数
    就可以保证_round_robin执行三次这部分代码会执行一次,因为count只有在_round_robin
    中会被加一。这部分代码就是选择一个choked和interested同时为真的连接放到列表的开头
    (不要让喜欢你的人等待太久)。
        在_rechoke()中,首先选择出一些符合解除choked状态的连接(条件是interested和下
    载方向的is_snubbed,即当前时间是否距离上次下载到东西的时间过短),然后把所有的这
    些连接按照下载的速度排序,由于前面增加了一个负号,因此下载速度最块的排在前面。然
    后根据配置项中的最大上传数计算一个配额,这个配额不能等于最大上传数,最多只能对于
    这个数减一,从这个列表中取出排名前面的若干位,设置一个mask标志。下面计算出最小上
    传数,count。count至少要为一,如果最小上传数比前面的配额还大,那么count也相应增
    大。下面就是解除choke状态了,首先mask为1的,无条件解除,如果mask不为1,但是
    count还大于0,那么用掉一个count,解除choke状态,其它的连接,一律choke掉。
        Upload的choke和unchoke都是在确定状态改变的情况下,开始向对方通知这一消息。
        这一次结合连接中开始的部分消息交互过程,介绍了choker这一阻塞策略管理器的工作
    原理。下一次将开始介绍在连接的双方的已经同意交换数据(choked为假而interested为真
    )时的情况。
  • 相关阅读:
    解决跨域问题 cors~ JSONP~
    session,cookie,sessionStorage,localStorage的区别~~~前端面试
    数据库索引的理解
    script的按需加载
    es6 笔记
    JS 工具函数
    JS Error
    数组方法重写:forEach, map, filter, every, some, reduce
    JS: GO 和 AO
    立即执行函数
  • 原文地址:https://www.cnblogs.com/kokoliu/p/616929.html
Copyright © 2020-2023  润新知