您的位置:首页 > 理论基础 > 计算机网络

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

2007-03-14 13:35 736 查看
BT源代码学习心得(七):跟踪服务器(Tracker)的代码分析(HTTP协议处理对象)
author: wolfenstein (NeverSayNever)

上次我们分析了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,首先去除空格,然后把它们按照空格符分开,如果有三个词,那么认定它的格式为commandpath 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 404Not Found),HTTP回应头部数据和正文数据的四元组返回即可。
下一次,我们就可以很仔细得看Tracker到底是如何得处理用户请求了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐