手记

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

0人推荐
随时随地看视频
慕课网APP