• BT源代码学习心得(七):跟踪服务器(Tracker)的代码分析(HTTP协议处理对象)


    BT源代码学习心得(七):跟踪服务器(Tracker)的代码分析(HTTP协议处理对象)

    发信人: wolfenstein (NeverSayNever), 个人文集
    标  题: BT源代码学习心得(七):跟踪服务器(Tracker)的代码分析(HTTP协议处理对象)
    发信站: 水木社区 (Mon Aug  8 21:45:42 2005), 文集
    (本文包含HTML标记,终端模式下可能无法正确浏览)
        上次我们分析了Tracker类初始化的过程,现在开始具体看跟踪服务器是如何提供服务
    的。
        首先分析Tracker处理对象是HTTPHandler,它定义在BitTorrent/HTTPHandler.py中,
    这个对象的初始化函数很简单,只是把Tracker.get函数赋值到自己的一个内部变量备用。
    当有外部网络连接到达时,根据前面对RawServer的分析,我们知道,
    HTTPHandler.external_connection_made函数会被调用,它维护了自己内部的一个字典
    connections,以传进来的参数connection(它的类型是SingleSocket)为关键字,值为一个
    新建立的HTTPConnection,新建立的HTTPConnection也主要是进行一些值的初始化,另外注
    意这句:
        self.next_func = self.read_type
        这个变量被指向自己的一个函数,后面我们还会看到,它还会发生变化,以灵活处理数
    据的不同部分。
        现在可以分析客户端和跟踪服务器的网络通讯协议了。当有数据到达时,
    HTTPHandler.data_came_in会被调用,从它的代码中我们可以一眼看出,起主要作用的其实
    是该网络连接对应的HTTPConnection的data_came_in函数,它首先检查donereading标志和
    next_func函数,即如果已经完成读的操作或者没有next_func来处理下一步,都直接返回,
    然后将data(网络中读到的数据)添加到自己内部的buf中,下面是一个while循环,可以看出
    ,它的做法是每次从网络数据中寻找\n值,以该值做为两个不同的处理单元,然后将这个回
    车前面的部分赋值到val,后面的部分赋值到buf(就相当于buf在这个回车前面的部分砍掉,
    剩下的留待下一次处理),然后将这个val交由next_func处理,处理的结果返回给
    next_func,意思就是在next_func里处理完这部分值后,它很清楚下面一部分该由哪个函数
    处理,然后将next_func重新定向到它就行了,最后进行一些检查看看还要不要继续处理。
    这个函数我们可以看出,设计得比较巧妙,能够自动得把一个协议的不同的部分分到不同的
    函数进行处理,而且即使网络阻塞了,只来了一部分数据,下次又来一部分数据,只要它和
    buf一整合,next_func永远指向处理下一部分数据的函数。
        从HTTPConnection的初始化过程我们知道,第一部分的数据处理的函数read_type,首
    先去除空格,然后把它们按照空格符分开,如果有三个词,那么认定它的格式为command
    path garbage,否则,认为是command path。然后检查command必须是GET或者HEAD,现在也
    已经可以猜出来path应该是一个URL路径,至此,我们可以看出,客户端和跟踪服务器的通
    信协议其实就是HTTP协议。接下来就是read_header来读取HTTP的头部。它首先看有没有数
    据,如果有的话,很简单,只是维护一个字典headers,且寻找到':',':'之前的就是关键
    字,之后的就是值,然后next_func还是read_header,就是说,剩下的数据都是一行一行的
    头部信息。全部读完后,检查headers里面有没有accept-encoding项,这项指定返回的数据
    的编码方式,只有两种,普通模式('identity')和压缩模式('gzip'),然后调用getfunc,
    其实就是Tracker.get来正式处理用户的HTTP请求,而且已经把请求转化成比较方便的参数
    ,即path(用户的请求URL)和headers信息。处理完毕后,如果返回的结果不是None的话,则
    调用answer把处理结果返回给用户。
        我们先看answer,看到它的参数,我们就知道,它把返回的结果转化成HTTP协议的要求
    。传给它的参数是一个元组,包含回应代码,回应字符串,头部数据,正文数据四部分。它
    首先看是否要压缩,如果是的话,就进行压缩,但是压缩后它把压缩后的数据和之前的数据
    进行长度比较,如果压缩后数据反而更长,那么就不压缩了。接下来是进行日志的记录,诸
    如某年某月某日某时某分某人在这里请求了某物,返回了某些数据等等。前面我们注意到在
    Tracker初始化的时候已经把标准输出重定向到日志文件中了,因此这里的print其实就是往
    日志文件中写。然后用一个StringIO来处理字符串的操作,可以不断得往里面write,我们
    看到,程序按照标准的HTTP应答格式("HTTP 1.0 XXX ResponseStringBlablabla..\n")的格
    式,全部处理完后,一次性地往connection里write,把它传送到网络里,RawServer里面已
    经帮我们处理好了网络阻塞之类的问题,然后检查,如果数据全部写出去了,那么就关闭这
    个连接。HTTP协议也确实是这样的,一个请求,一个回应,就完成了。
        现在我们可以看到,在BT中客户端和跟踪服务器之间的通信协议就是HTTP协议,而且
    HTTPHandler和HTTPConnection已经把HTTP的很细节的部分全部都处理好了,这就意味着
    Tracker.get已经得到了一个连接对象,一个用户请求的地址,以及一个字典类型的HTTP请
    求头部数据,并且这个函数只需要专心得完成处理,并把处理的结果以包含HTTP回应代码
    (200,404,500等),回应字符串(如Not Found,这样和前面的代码合起来就是HTTP 1.0 404
    Not Found),HTTP回应头部数据和正文数据的四元组返回即可。
        下一次,我们就可以很仔细得看Tracker到底是如何得处理用户请求了。 
  • 相关阅读:
    Oracle创建序列,删除序列
    java base58
    百度地图 显示,定位,轮廓图
    百度地图 圈出省份轮廓图并高亮
    基于双向链表的增删改查和排序(C++实现)
    统计字母出现次数
    线程安全
    C++面试秘笈笔记
    牛客选择题刷题
    new delete 浅析
  • 原文地址:https://www.cnblogs.com/kokoliu/p/616914.html
Copyright © 2020-2023  润新知