SimpleHTTPSever模块的分析

SimpleHTTPServer.py模块是用来建http站点的一个很有用的模块,看完了它的源代码后,就分析了一下它的结构,留着做以后的参考

SimpleHTTPServer.py里面就一个class: SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler)

/*SimpleHTTPRequestHandler 简记为SimpleHRH
/*BaseHTTPRequestHandler 简记为BaseHRH

直接看它的代码是很难看懂的,我从最根源的模块开始分析。即SocketServer.py,
然后看BaseHTTPServer.py模块,最后看SimpleHTTPServer.py.

SocketServer.py这个模块中有8个主要的class,如下
BaseServer, TCPServer, UDPServer, BaseRequestHandler, ForkingMixIn,ThreadingMixIn,StreamRequestHandler, DatagramRequestHandler


——————————————————————————————————————

首先是BaseServer,它是直接定义的,没有父类,因此是根类。
它有2个变量server_address, RequestHandlerClass.他们的用处从名字就看出来了
第1个是服务器的地址, 第2个是用来处理客户请求的类的引用, 他们在__init__中就声明好了。
BaseServer的函数如下:
函数名              函数中依次调用其他函数
server_activate    空函数
server_close       空函数
close_request      空函数
server_forever     在无限的循环中调用handle_request
verify_request     始终返回True
handle_request     get_request, verify_request, process_request
process_request    finish_request, close_request
finish_request     构造出RequestHandlerClass的一个实例(处理请求用)
handle_error       处理error的函数,我忽略了

注意,handle_request调用了get_request函数,但这个类里面根本就没有定义
get_request。不要紧,在BaseServer的子类中都会补上get_request的。

整个类中函数的调用框架如下:
server_forever -> handle_request -> get_request -> verify_request
-> process_request -> finish_request -> close_request -> handle_request

因为server_forever是在无限的循环中调用handle_request,因此上面的链到达close_request时,就处理完了一个请求,然后回到handle_request

仔细看这个类的函数,可以发现这个类其实什么事都没有干,这是真的,因为它连一个
socket都没有,能干什么事呢?这个类的主要用处就是要建立上面的那个循环调用链,
也就是构建出服务器的监听,处理请求的结构,后面的类就是要来修改这个类的某些函数
这个类是个abstract class


——————————————————————————————————————
接下来拿TCPServer开刀,看定义如下:
class TCPServer(BaseServer)
它从BaseServer继承而来,也有上面的调用链,它必须做出一些修改。
首先,它加入了4个类全局变量(c++里面叫static变量,忘了python里面叫什么)
address_family = socket.AF_INET
socket_type = socket.SOCK_STREAM
request_queue_size = 5
allow_reuse_address = False
它们分别定义了socket的family,type,队列的大小,从用地址。看来,TCPSever将是
第一个有socket的类。果然,它的__init__里面如下:
BaseServer.__init__(self, server_address, RequestHandlerClass)
self.socket = socket.socket(self.address_family,self.socket_type)
self.server_bind()
self.server_activate()

建立socket, 绑定socket,再activate(),一气呵成。
server_activate()是BaseSever的一个空函数,TCPServer改写了它,在该函数中加入了socket.listen()的调用。这样,TCPServer类一旦创建,就直接进入了listen状态。

TCPServer修改或添加的函数如下:
函数名              函数中依次调用其他函数
server_activate    socket.listen
server_close       socket.close (关listen的socket)
close_requset      socket.close (关accept返回的socket)
get_request (+)    socket.accept
server_bind (+)    socket.bind
fileno      (+)    socket.fileno (select中要用的)

上面带(+)的表示是TCPServer添加的。
把这些函数带入BaseServer的调用链中,就可以看出TCPServer已经可以接受client的连接了,但还不能回复。这个回复过程将在finish_request中完成,但不是由TCPServer来做。


——————————————————————————————————————
再看看UDPServer。
class UDPServer(TCPServer)
从TCPServer继承来的,首先就要把type改了, 然后添加包的大小上限max_packet_size = 8192。
UDPServer函数的改动很少。udp是无连接的,因此server_activate, close_request函数体又变成了空.因为不能用accept,get_request就改调用recvfrom了。


——————————————————————————————————————
接下来是多进程处理了ForkingMixIn
它没有父类,直接定义的,有两个类全局变量active_children, max_children.
第1个是纪录子进程的pid的列表,第2个是最多子进程数量,为40。
这个类就2个函数
collect_children 用来收集zombie进程的,调用了os.waitpid
process_request  很眼熟的函数吧,就是这儿改写了BaseSever中的那个函数。如果要使服务器是多进程的,多重继承时一定要把ForkingMixIn放在BaseSever前面。

process_request 负责fork出子进程,并在父进程中调用close_request,在子进程中
调用finish_request,它把BaseSever中的调用链稍微改了一下,后面的部分如下:

                                    parent:     |——> close_request
                                               /
process_request -> collect_children -> fork ->+
                                               \
                                    children:   |——> finish_request



——————————————————————————————————————
然后是多线程ThreadingMixIn
一个类全局变量daemon_threads用来设定线程是否为daemon
两个函数:process_request_thread, process_request,函数调用如下:
process_request_thread -> finish_request -> close_request

                              |-----> return
                             /  
process_request -> Thread ->+
                             \
                              |-----> process_request_thread



这是几个多重继承的类:
class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass



——————————————————————————————————————
接下来考虑如何finish_request了
首先又是一个abstract root class,什么都不做,就建一个框架。这个类名字还长
BaseRequestHandler
3个变量self.request,self.client_address,self.server
3个空函数setup, handle, finish

它构造的函数链如下:
__init__ -> setup -> handle -> finish


他的第一个子类:StreamRequestHandler处理流socket的类,专为Tcp类型的服务
它的setup用来建立对socket读写的文件对象,finish关闭这些对像,handle还是空的

另一个子类:DatagramRequestHandler处理数据报socket,3个函数的功能和
StreamRequestHandler里的一样,只是实现的方法不同, setup打开一个stringIO
finish则用sendto发出这个stringIO.


SocketServer.py就是由上面的几个类组成的。
该看BaseHTTPServer.py了

这个模块里面有2个类:HTTPServer, BaseHTTPRequestHandler

HTTPServer是继承至TCPServer的,它只改写了server_bind函数。这个函数先调用
TCPServer的server_bind,接着纪录下服务器本身的地址和断口号。

BaseHTTPRequestHandler的内容就比较多了,它继承至StreamRequestHandler.
StreamRequestHandler中只有handle是空函数,要改写它,但不急,先看看
BaseHTTPRequestHandler的函数列表
函数名              函数说明
parse_request      分析请求
handle_one_request 完整的处理一个请求
handle             改写了
send_error
send_response
send_header
end_header
log系列的函数
string 系列的函数

现在的函数链是这样的:
handle -> handle_one_request -> parse_request -> ?

(1) do_method
(2) send_error -> send_respone -> send_header -> end_header

第一条链到达?时程序要判断client发来的请求.
请求有GET, HEAD, POST 等等。
例如发过来的请求是GET, 就到(1)试着调用do_GET函数,如果类没有提供do_GET函数
就去(2),发送出错信息。这个类本身没有提供do_GET, do_HEAD等功能,因此不管client发什么请求,都是收到出错提示。但有些类会继承这个类,他们会提供某些
do_method,那时就没有出错提示了



这个BaseHTTPServer.py简单多了。
终于可以看SimpleHTTPServer.py了

开头就提到了,这个模块里面就一个类,继承至BaseHTTPRequestHandler
它提供了do_GET和do_HEAD两个方法,可以支持GET, HEAD请求

函数列表如下:
do_GET
do_HEAD
send_head
list_directory
translate_path
copyfile
guess_type

函数调用如下:
do_GET -> send_head() -> copyfile
do_HEAD -> send_head()

上面函数列表中的后5个函数是辅助函数,如果要写服务器程序,直接继承
SimpleHTTPRequestHandler,在改写do_GET和do_HEAD就可以了。
要支持POST方法,就找CGIHTTPServer.py模块继承CGIHTTPRequestHandler。

最后,试一试服务器,直接运行SimpleHTTPServer.py,打开IE浏览器,输入
http://自己的IP地址:8000
就可以看到服务器的正常运行了。