BT源代码学习心得(五):统一网络服务接口--RawServer
author:wolfenstein

以后的部分都需要网络服务(种子文件的生成在本地就可以完成,但是通过这些种子文件下载实际的内容和提供跟踪器服务都需要网络),在BT的程序设计中,为 网络服务提供了统一的接口,这样程序中的其它部分需要打开一个网络服务时,只需要向这个接口进行注册,并提供相应的处理对象(handler)即可,当网 络事件发生时,将会自动这个处理对象中的相关函数进行处理。
    这个统一网络服务接口定义在BitTorrent/RawServer.py中,由它去实际调用和网络插口(socket)有关的库,另外,RawServer还提供add_task功能,可以允许一些任务被延后执行。
    RawServer在初始化的时候,可以从外部传入一个doneflag参数,这是一个Event的数据类型,可以从其它地方触发它,这样可以随时中断 RawServer中的主循环(listen_forever中的)。另外还进行一些内部变量的设置。最后,它给自己增加了一个任 务,scan_for_timeouts,这个任务会定时得检查超时的网络连接,并关闭它们。
    我们可以看到add_task的所做的工作就是将要延时执行的任务计算出它的实际执行时间,并把它添加到一个排好序的列表中(funcs),且保持这个列表仍然处于有序状态,这个列表以实际执行时间为顺序。
    当其它模块要提供网络服务时,它首先调用RawServer的create_serversocket函数,这个函数会返回一个socket对象,并且这 个socket返回时,已经处于listen状态了。当然,这个时候如果真有外部的网络连接进来,还是不会有什么动作的,因为相应的处理对象还没有注册进 来。
    接下来应该调用start_listening函数,这个函数的作用是把得到的网络插口和它对应的处理对象添加到一个字典中,该字典以网络插口的描述符 (FD)为主键。值得注意的是,这个函数名称中虽然有listen字样,但是socket.listen函数却不是在这里调用,而是在 create_serversocket就已经被调用了。传递进来的处理对象的类型没有限制,唯一的要求是它必须包含有 external_connection_made函数,这样当外部网络连接到来时,这个函数就会被调用。处理对象通常还应提供data_came_in 函数来处理网络数据,以及connection_flushed函数来处理数据已经正式发出(相对于还在缓冲区的情况)时的处理,后面两个函数也可以不提 供,因为在external_connection_made函数里,可以把新连接的网络数据处理对象重新定位到一个包含有data_came_in函数 和connection_flushed函数的对象。
start_listening函数处理完后,该网络插口就已经存在于serversockets字典中了。
    而当其它模块要连接到外部网络时,应该调用start_connection函数,这个函数将把网络插口添加到另一个字典single_sockets 中,当然,使用了SingleSocket对象对其进行了一定程度的包装。从后面的分析可以看到,这个SingleSocket对象的主要功能是对输出的 数据进行了一定的缓冲,并在不会阻塞的情况下把这些数据实际得写到socket中。
start_connection需要传入的处理对象是必须包含data_came_in而可以不包含external_connection_made的对象。
    在start_listening和start_connection中都用到了poll对象,这是系统提供的一个提供轮询机制的模块,使用文件描述符作 为参数,可以得到相应的事件(即该文件描述符对应的插口有数据流入或者留出等),而在这两个函数中,都调用了poll的注册函数,方便后面的poll轮询 操作。
    需要注意的是,在上面的这些函数被执行后,网络连接还是不会被处理,因为虽然打开了相应的网络插口,也注册了相应的处理对象,但是整个的轮询机制还没有建 立起来。直到listen_forever函数被调用后,这个机制才真正得建立起来。这个函数的主体就是一个无限的while循环,只有doneflag 这个事件可以被用来中止这个循环。它首先做的事情是从添加的任务funcs寻找最近要执行的任务的时间,并与当前时间相减,计算出period,然后用 poll轮询这么长的时间,这样做就可以保证轮询结束后不会耽误外部任务过久。轮询到的结果返回在events里,这是一个列表,它的元素是以文件描述符 和事件所组成的二元组。接下来就是根据时间的情况,把需要马上执行的外部任务都执行了,_make_wrapped_call的主要作用就是执行外部任 务,只是给它们增加一些意外处理的保护代码。执行完这些外部任务后,调用_close_dead关闭不活跃的网络连接,接下来就是使用 _handle_events来处理前面的poll搜集到的网络事件了。
    _handle_events的主体是一个for循环,检查每一个sock和它对应的event。首先看它是在serversockets字典中还是在 single_sockets字典中,如果是前者,那么这是一个侦听中的插口,再检查网络事件,如果不是出错事件的话,那么就说明是有外部连接到达,熟悉 socket编程的人都应该知道,这时正确的处理方式是建立一个新的socket,然后让侦听中的插口去accept它,以后数据的读写应该在新的 socket中进行。接下来的处理也是这样,新的socket被用SingleSocket包装起来了,并且也被放到single_sockets字典 中,因为它和用start_connection建立的socket一样,都是有可能有数据流入的,而侦听的插口只需要处理网络连接。接下来,前面注册的 处理对象中的external_connection_made函数被调用了,允许进行一些其它的相关操作,我们注意到,这里处理对象被原封不动得传入到 新的SingleSocket中,当然实际上在external_connection_made函数中可以把SingleSocket的处理对象重定向 到其它对象中。
    接下来的else语句说明sock在single_sockets字典中,只有一种情况例外,就是os.pipe。这种情况下不用处理这个事件,直接 continue处理下一个事件即可。然后检查事件,如果是出错则关闭该插口,否则就说明是有数据流动,而数据流动无非是流入和流出两种情况,如果是流入 的话,就把数据读到一个缓冲区里,然后调用处理对象中提供的data_came_in进行处理,而data_came_in得到的参数直接就是缓冲区中的 数据,它不需要再
处理socket以及考虑可能会形成的阻塞等问题了。另外由于SingleSocket中对写操作也进行了包装,即如果网络有阻 塞的可能,数据也会先写入缓冲区,这样data_came_in中就可以随便调用s.write了。最后如果是数据流出,则调用s.try_write, 这个函数实现得也很安全。
    最后检查是否数据都已经真的发出去了(flushed),如果是,则调用处理对象中提供的connection_flushed函数进行收尾工作。
    以后我们可以看到,在BT的实现中,创建了各种各样的对象,而且这些对象之间有各种各样比较复杂的关系,但是所有的网络服务,都是通过RawServer 来进行的,再具体一些,那就是RawServer这个对象只会被创建一个,而所有要求网络服务的模块都会把网络服务的处理对象注册到这个 RawServer中,方便统一管理。
    最后说一下,今天用google搜索发现原来去年就已经有人分析过BT的源代码,不仅感叹自己孤陋寡闻,不过发现现在的版本(4.0.3)和当时的版本已 经有了一些差别,而且我也可以以我的阅读源代码的思路继续前进,提供给大家一个不同的视角,因而决定把我的学习心得继续写完,希望大家能够支持。

BT源代码学习心得(五):统一网络服务接口--RawServer -- 转贴自 wolfenstein (NeverSayNever)相关推荐

  1. BT源代码学习心得(四):种子文件的生成 -- 转贴自wolfenstein (NeverSayNever)

    BT源代码学习心得(四):种子文件的生成 author: wolfenstein 在知道种子文件采取的编码方式后,我们现在可以来看一个种子文件具体是如何生成的了.在BT中,生成种子文件的可执行模块是 ...

  2. BT源代码学习心得(二):程序运行参数的获取 -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(二):程序运行参数的获取 发信人: wolfenstein (NeverSayNever), 个人文集 标  题: BT源代码学习心得(二):程序运行参数的获取 发信站: 水木社区 ...

  3. BT源代码学习心得(十五):客户端源代码分析(下载过程中的块选取策略)

    BT源代码学习心得(十五):客户端源代码分析(下载过程中的块选取策略) 发信人: wolfenstein (NeverSayNever), 个人文集 标  题: BT源代码学习心得(十五):客户端源代 ...

  4. BT源代码学习心得(十):客户端源代码分析(相关对象一览) -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(十):客户端源代码分析(相关对象一览) Author:wolfenstein(NeverSayNever), BitTorrent/download.py中的Multitorren ...

  5. BT源代码学习心得(七):跟踪服务器(Tracker)的代码分析(HTTP协议处理对象) -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(七):跟踪服务器(Tracker)的代码分析(HTTP协议处理对象) author: wolfenstein (NeverSayNever) 上次我们分析了Tracker类初始化的 ...

  6. BT源代码学习心得(六):跟踪服务器(Tracker)的代码分析(初始化) -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(六):跟踪服务器(Tracker)的代码分析(初始化) author:wolfenstein Tracker在BT中是一个很重要的部分.这个名词我注意到以前的文章中都是直接引用,没 ...

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

    BT源代码学习心得(六):跟踪服务器(Tracker)的代码分析(初始化) 发信人: wolfenstein (NeverSayNever), 个人文集 标  题: BT源代码学习心得(六):跟踪服务 ...

  8. BT源代码学习心得(九):客户端源代码分析(图形界面浅析) -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(九):客户端源代码分析(图形界面浅析)  author:wolfenstein 客户端将从btdownloadgui.py开始进行分析,这样可以顺便把Python中的GUI编程也看 ...

  9. BT源代码学习心得(八):跟踪服务器(Tracker)的代码分析(用户请求的实际处理) - 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(八):跟踪服务器(Tracker)的代码分析(用户请求的实际处理) author: wolfenstein 通过上一次的分析,我们已经知道了Tracker采用http协议和客户端通 ...

最新文章

  1. PornHub:修复百年前情色电影
  2. 如何用Node调用腾讯AI图像服务
  3. 解决 Virtual PC 在 XP PAE模式下无法运行的问题
  4. Autodesk MotionBuilder 2020中文版
  5. 基于.Net 2.0 (C# 2.0, ASP.NET 2.0)的快速Web开发框架设计
  6. hurricane中文_hurricane是什么意思
  7. unreal world 皮革_UnRealWorld 进阶游戏教程
  8. java 反射执行语句_JAVA反射机制
  9. 富士康已看到芯片短缺开始缓解迹象 预计下半年会有改善
  10. 微服务架构工作笔记001---认识Service Mesh
  11. 跨语言之间的socket通信(C--Java的握手)(基础篇转)
  12. 天津联通移动电信DNS
  13. 小姜的毕设_Software
  14. Python有多难?可以自学吗?
  15. 51物联卡:浅谈物联网卡在智能安防中的发展前景
  16. php英文月份,月份英文、月份英文的縮寫│English Learning線上免費英文學習網、線上英文...
  17. PDN connection
  18. 关于时间:UTC/GMT/xST/ xDT
  19. 量子计算机与低温,逼近绝对零度,和外太空一样的低温_服务器评测与技术-中关村在线...
  20. 全球及中国小型风力发电行业研究及十四五规划分析报告(2022)

热门文章

  1. 微信公众平台开发最佳实践
  2. 计算机怎么打开隐藏的项目,展示win10系统怎么打开隐藏文件夹
  3. mac 启动台不显示已经安装的软件图标
  4. efi模式装linux双系统,超详细!Win10(UEFI启动模式)安装Ubuntu18.04双系统
  5. 联想电脑拯救者y7000触摸屏失灵的修复方法
  6. 我的世界服务端大全-服务器插件等相关网站推荐
  7. Kali/Ubuntu GVM (openvas)安装及使用
  8. vue前端使用jsencrypt RSA 加解密插件
  9. Symmetric Difference
  10. matlab根据根求多项式,matlab求解多项式的根