SimpleHTTPSever模块的分析
时间:2006-03-10 来源:xxandxx
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 就可以看到服务器的正常运行了。
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 就可以看到服务器的正常运行了。
相关阅读 更多 +