Python 的 BaseHTTPServer模块分析小结

已经好久没更新过博客了,因为最近开始用为知笔记了,感觉每次发到blog的都太零散了,好多都还没完成,所以现在决定,零散的写到笔记里去,然后有一个完整的内容再发到blog里来。

这次是一篇完整的BaseHTTPServer模块分析,花了几天时间研究该模块,先放上我的思维导图,由于是第一次使用思维导图,所以弄得不是很满意。
BaseHTTPServer

分析该模块的起因是该反代程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import BaseHTTPServer
import hashlib
import os
import urllib2

class CacheHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
m = hashlib.md5()
m.update(self.path)
cache_filename = m.hexdigest()
if os.path.exists(cache_filename):
print "Cache hit"
data = open(cache_filename).readlines()
else:
print "Cache miss"
data = urllib2.urlopen("http://www.baidu.com" + self.path).readlines()
open(cache_filename, 'wb').writelines(data)
self.send_response(200)
self.end_headers()
self.wfile.writelines(data)

def run():
server_address = ('', 9999)
httpd = BaseHTTPServer.HTTPServer(server_address, CacheHandler)
httpd.serve_forever()

if __name__ == '__main__':
run()

BaseHTTPServer

在该模块中定义了两个类

  • HTTPServer
  • BaseHTTPRequestHandler

HTTPServer(SocketServer.TCPServer)

该类中为定义 init()初始化函数,所以跳到它继承的 SocketServer.TCPServer中去

TCPServer(BaseServer)

_init_ 接收两个必填参数,和一个可选参数。
前两个参数到他继承的BaseServer中初始化
这两个参数一个是需要监听的地址和端口, 一个是类
然后就是建立一个socket链接 self.socket = socket.socket(self.address_family, self.socket_type)
然后是

1
2
3
4
5
6
try:
self.server_bind()
self.server_activate()
except:
self.server_close()
raise

如果传了第三个参数,值为False,则不执行上面的代码
然后,初始化完毕

server_bind(self)

(这重名字就能猜到大概,所以说,编程是命名要有意义!)
根据前面初始化的地址,绑定地址端口。
也就是socket编程中的 socket.bind()

server_activate(self)

写过socket服务的就知道了,绑定完后就是监听了.
默认是5个客户端.
socket.listen(5)

get_request(self)

没啥好说的, 返回 socket.accept()

BaseServer

__init__ 接收两个参数,然后赋值给self.

serve_forever(self, poll_interval=0.5)

上面的反代程序中,初始化完后就是执行该方法,由于上面都没有定义过,所以就跑到这来执行了。
先是去执行 select.select([self], [], [], 0.5) (select还未研究透彻)
接着执行 _handle_request_noblock()

_handle_request_noblock(self)

先是执行 get_request()(该类里竟然没有该方法,在TCPServer里有)
接着把accept返回的两个值传给 process_request 方法

process_request(self, request, client_address)
1
2
self.finish_request(request, client_address)
self.shutdown_request(request)
finish_request(self, request, client_address)
1
self.RequestHandlerClass(request, client_address, self)

RequestHandlerClass 是初始化的时候传入的第二个类参数
所以HTTPServer类的主体部分基本结束了,接下来是运行传入的模块

shutdown_request(self, request)
1
self.close_request(request)
close_request(self, request)
1
pass

上面反代的程序中,传入的是 CacheHandler类

CacheHandler(BaseHTTPServer.BaseHTTPRequestHandler)

没有 _init_ 所以看它继承的类

BaseHTTPRequestHandler(SocketServer.StreamRequestHandler)

也没有_init_ 所以继续看它继承的类

handle(self)

执行 handle_one_request()
有一个参数 close_connection = 1 但为0的时候循环执行上面这个方法

handle_one_request(self)

该方法每执行一次,从文件中读取一行,接着超蛋疼!
因为它只读一行!本以为上面那个方法每次循环读一行,然后获取所有headers,但是实际上只获取
GET / HTTP/1.1
该类初始化赋值的时候,赋值了一个 default_request_version = "HTTP/0.9"
但是却要该值 >= HTTP/1.1 才把 close_connection 设置为0
接下来就是执行 'do_' + method, 啥意思?
比如上面的,GET / HTTP/1.1 代码会把这串字符串分成三部分,而GET就是method,所以说,如果是 POST / HTTP/1.1则是执行 do_POST 方法,但是由于该反代只写了 do_GET 所以只能接收GET方法

StreamRequestHandler(BaseRequestHandler)

还是没有 _init_ 接着看下去

setup(self)

socket.accept() 返回的socket对象有个makefile方法,就是把收到的数据当成文件来读,返回的数据当文件来写,

1
2
self.rfile = self.connection.makefile('rb', self.rbufsize)
self.wfile = self.connection.makefile('wb', self.wbufsize)

finish(self)

把上面打开的读写文件都关闭

BaseRequestHandler

接收三个值,初始化给self, 然后执行

1
2
3
setup()
handle()
finish()

这三个方法.

文章目录
  1. 1. BaseHTTPServer
    1. 1.1. HTTPServer(SocketServer.TCPServer)
      1. 1.1.1. TCPServer(BaseServer)
        1. 1.1.1.1. server_bind(self)
        2. 1.1.1.2. server_activate(self)
        3. 1.1.1.3. get_request(self)
        4. 1.1.1.4. BaseServer
          1. 1.1.1.4.1. serve_forever(self, poll_interval=0.5)
          2. 1.1.1.4.2. _handle_request_noblock(self)
          3. 1.1.1.4.3. process_request(self, request, client_address)
          4. 1.1.1.4.4. finish_request(self, request, client_address)
          5. 1.1.1.4.5. shutdown_request(self, request)
          6. 1.1.1.4.6. close_request(self, request)
  2. 2. CacheHandler(BaseHTTPServer.BaseHTTPRequestHandler)
    1. 2.1. BaseHTTPRequestHandler(SocketServer.StreamRequestHandler)
      1. 2.1.1. handle(self)
      2. 2.1.2. handle_one_request(self)
      3. 2.1.3. StreamRequestHandler(BaseRequestHandler)
        1. 2.1.3.1. setup(self)
        2. 2.1.3.2. finish(self)
        3. 2.1.3.3. BaseRequestHandler