已经好久没更新过博客了,因为最近开始用为知笔记了,感觉每次发到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()
在该模块中定义了两个类
该类中为定义 init ()初始化函数,所以跳到它继承的 SocketServer.TCPServer
中去
_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,则不执行上面的代码然后,初始化完毕
(这重名字就能猜到大概,所以说,编程是命名要有意义!)
根据前面初始化的地址,绑定地址端口。
也就是socket编程中的 socket.bind()
写过socket服务的就知道了,绑定完后就是监听了.
默认是5个客户端.
socket.listen(5)
没啥好说的, 返回 socket.accept()
_init_ 接收两个参数,然后赋值给self.
上面的反代程序中,初始化完后就是执行该方法,由于上面都没有定义过,所以就跑到这来执行了。
先是去执行 select.select([self], [], [], 0.5)
(select还未研究透彻)
接着执行 _handle_request_noblock()
先是执行 get_request()
(该类里竟然没有该方法,在TCPServer里有)
接着把accept返回的两个值传给 process_request
方法
self.finish_request(request, client_address)
self.shutdown_request(request)
self.RequestHandlerClass(request, client_address, self)
RequestHandlerClass 是初始化的时候传入的第二个类参数所以HTTPServer类的主体部分基本结束了,接下来是运行传入的模块
shutdown_request(self, request) self.close_request(request) close_request(self, request) pass
上面反代的程序中,传入的是 CacheHandler类
没有 _init _ 所以看它继承的类
也没有 _init _ 所以继续看它继承的类
执行 handle_one_request()
有一个参数 close_connection = 1
但为0的时候循环执行上面这个方法
该方法每执行一次,从文件中读取一行,接着超蛋疼!
因为它只读一行!本以为上面那个方法每次循环读一行,然后获取所有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方法
还是没有 _init _ 接着看下去
socket.accept() 返回的socket对象有个makefile方法,就是把收到的数据当成文件来读,返回的数据当文件来写,
self.rfile = self.connection.makefile('rb', self.rbufsize) self.wfile = self.connection.makefile('wb', self.wbufsize)
把上面打开的读写文件都关闭
接收三个值,初始化给self, 然后执行
setup() handle() finish()
这三个方法.
已经好久没更新过博客了,因为最近开始用为知笔记了,感觉每次发到blog的都太零散了,好多都还没完成,所以现在决定,零散的写到笔记里去,然后有一个完整的内容再发到blog里来。