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

来源:互联网 发布:portal软件 编辑:程序博客网 时间:2024/06/05 11:46

BT源代码学习心得(八):跟踪服务器(Tracker)的代码分析(用户请求的实际处理)
author: wolfenstein

    通过上一次的分析,我们已经知道了Tracker采用http协议和客户端通信,这一次我们就可以直接分析Tracker.get函数的代码,看看跟踪服务器是如何处理用户的请求的。
    首先是检查IP,一个是通过网络连接直接得到的IP(这个有可能是对方的http代理服务器的IP),另一个是从请求的头部数据中解析出来的IP,通过分 析函数get_forwarded_ip和_get_forwarded_ip我们可以发现,它的原理是从头部数据中看有没有这些关键 字:http_x_forwarded_for,http_client_ip,http_via,http_from,如果有的话,就说明当前的 http连接中的网络的另一头是一个代理服务器,而不是实际的客户端,有些http代理服务器会提交这些http请求的头部数据告诉服务器客户端的真实 IP地址。还有就是要检查这些IP地址是否合法,是否为本地地址 (10.*.*.*,127.*.*.*,169.254.*.*,172.16.*.*-172.31.*.*,192.168.*.*)等,然后确认 真实的IP值。接下来准备好paramslist准备处理请求参数,这是一个字典,但是它的每个元素的值是一个列表,这种情况在http请求的参数列表中 很常见。
    接下来用urlparse把用户的http请求分成标准的几部分,例如,类似如下的请求:
     [ 
http://xxx.xxx.xxx/path;parameters?query1=a&query2=b&query3=c#fragment ]
     
http://xxx.xxx.xxx/path;parameters?query1=a&query2=b&query3=c#fragment
    将被分割成这样的6块:http,xxx.xxx.xxx,path,parameters,query1=a&query2=b&query3=c,fragment
    接下来把query中的值按照'&'以及'='进行处理,把它们填入到paramslist中,确认出请求的参数。下面就是根据各种情况返回给用户适当的结果了。
    首先,如果用户请求路径是空的或者是'index.html'(对应于 [ 
http://xxx.xxx.xxx/http://xxx.xxx.xxx/或者 [ http://xxx.xxx.xxx/index.html ]http://xxx.xxx.xxx/index.html),那么就返回给用户一个信息页面,使用get_infopage函数完成,当然,在实际 运行中,可以把配置文件设置为不允许显示信息页面,这样get_infopage就会返回HTTP404代码,否则,生成一个页面文件,它包含了一些基本 信息,以及该跟踪服务器目前关注的种子文件的列表以及它们的一些统计情况。接下来的情况是用户请求路径'scrape'或者'file',也是返回相应的 信息给用户。其中,get_scrape返回的各个种子文件的统计信息,例如某个种子有多少下载完了,多少人还没下载完成等。而'
file'则是直接获取某个种子文件(即允许用户直接从跟踪服务器下载种子文件)。注意在以上的请求过程中,表示某个具体的种子文件的关键字是它的信息部分的消息摘要值(infohash)。
    在处理完另一种情况,用户要求返回图标文件后,接下来就是跟踪服务器的主要功能,announce了。所以如果路径不是announce的话,那就返回 HTTP404。下面先获取infohash,即客户端请求的是哪个种子文件的情况,然后进行check_allowed检查,排除有些种子不能在此跟踪 服务器上下载的情况。这样可以及时得对跟踪服务器做一些授权方面的操作,例如如果发现有人发布了有违反国家法律法规的内容的种子,跟踪服务器的维护人员只 需要及时得把这个种子的infohash添加到这个列表中,就再没有人可以下载这个种子了。
    在排除了各种意外的情况后,就可以用add_data把用户的信息添加进去了。一个跟踪服务器在获取了一个客户端要求下载某个种子文件的请求后,它把这个 客户的信息记录起来,这样他就知道有哪些客户对某个具体的种子文件感兴趣。然后再根据这些列表,选取一些客户的信息返回给客户,而要下载这个种子文件中的 实际共享资源?自己去找其它客户(客户称呼其它客户时应该叫对等客户)解决吧,跟踪服务器上一个字节都没有。
    add_data首先从downloads这个字典中找到关键字为infohash的项,赋值到peers中,如果downloads中没有这项,则新建 这项(setdefault,详见python库参考手册之内建类型字典的详细说明),然后检查传进来的参数是否合法,如peerid必须是20个字 节,event(如果有)只能是'started','completed','stopped','snooped'中的一项等。peers是一个以 peerid为关键字的字典,因此先看看原来有没有这个peer,用peerid把它取出来。然后准备好rsize,这个是返回的项(即返回多少个对等客 户的信息给客户)的数目,它由客户的要求以及服务器的配置参数共同决定。然后如果用户的请求中有event=stopped项,则删除该客户的信息,否 则,如果peer为空(peers中没有这个peerid的peer),则设置好一个新的peer的信息,然后添加进去,如果peer已经存在了,那么就 更新一下它的信息。最后返回rsize完成任务。其中有一个NAT处理的类,定义在BitTorrent/NatCheck.py中,它通过往用户声称的 IP和端口进行一次连接,看看有没有反应,以确认NAT情况,并且记录下来。最后还要把这些数据放到becache中,这个地方存放经过一定格式处理后的 客户数据,可以加快返回客户信息的函数的处理过程。becache中所有的客户信息都按照下载完成(做种)和未完成分开了,这个可以方便服务器返回一定的 做种peers和非做种peers给客户。
    在add_data把客户的数据更新好后,接下来就是用peerlist函数返回一定量的客户信息了。它根据用户的要求(rsize),以及所有的 peers中种子数占的比例,决定返回给客户的信息中,有多少是做种的peers,即返回给客户的做种peers占所有返回给客户的peers的比例,应 该接近于所有在下载这个种子的做种peers和全部peers的比例。然后把两部分的信息复制到一个cache中,再用shuffle把它们打乱,最后把 这些信息返回给客户。因此我们可以看到,跟踪服务器返回用户信息的准则是,在保持种子所占的比例接近全局的种子比例的情况下,随机选取客户信息返回给客 户。
   今天把跟踪服务器的代码全部分析完了,下一次就可以开始客户端源代码分析了。