转载

Python 的 BaseHTTPServer模块分析小结

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

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

查看大图

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

#!/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)

然后是

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)

self.finish_request(request, client_address)
self.shutdown_request(request)

finish_request(self, request, client_address)

self.RequestHandlerClass(request, client_address, self)

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

shutdown_request(self, request) self.close_request(request) close_request(self, request)     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方法,就是把收到的数据当成文件来读,返回的数据当文件来写,

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

finish(self)

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

BaseRequestHandler

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

setup() handle() finish() 

这三个方法.

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

原文  http://outofmemory.cn/python/python-BaseHTTPServer-module
正文到此结束
Loading...