1. SocketServer.py
1.1 整体结构
在基类中调用并不实现的方法;类似于C++的纯虚函数,强迫派生类实现。不一样的是,如果派生类中不调用(派生类的用户也不调用)该方法,那么派生类就可以不实现这个方法。
对某些函数提供一个空的实现,相当于JAVA的Adapter类,提供一个缺省实现。
RequestHandler的使用。并不是提供一个虚或者纯虚函数来处理网络请求,而是通过一个Handler类(或者函数,或者其它任何可以被调用的东西)来进行处理。
这就是传说中的Strategy 模式。
优点:处理网络请求和监听、接受网络请求相分离;松散耦合;无论哪个模块都更容易重用。
MixIn的结构更加优雅。
1.2 BaseServer结构
可以被调用,不能被覆盖的函数:
Ø
__init__(server_address,
RequestHandlerClass)
在 Base 中构造函数,保存
address 和 handler class,不调用任何函数。
在TCP中,构造 socket 对象,调用
server_bind和server_activate。
Ø
serve_forever()
循环处理每一个请求,直到世界末日 while True:
self.handle_request()
在
TCP中没有覆盖
在 UDP 中没有覆盖
Ø
handle_request() # if
you do not use serve_forever()
处理一个请求,在处理过程中,有可能产生阻塞。首先调用 get_request 获得一个请求;然后调用verify_request对请求进行验证;如果验证成功,调用process_request对请求进行处理;如果处理过程中发生错误,调用handl_error处理错误,调用close_request释放资源。
try:
request, client_address =
self.get_request()
except
socket.error:
return
if self.verify_request(request,
client_address):
try:
self.process_request(request,
client_address)
except:
self.handle_error(request,
client_address)
self.close_request(request)
在 TCP 中没有覆盖
在 UDP
中没有覆盖
Ø
fileno() -> int #
for select()
在 BaseServer中没有实现
在 TCP
中调用 socket.fileno
在 UDP 中没有覆盖
可以被覆盖的函数
Ø
server_bind()
在 Base
中没有实现
在 TCP 中调用
socket.bind
在 UDP 中没有覆盖
Ø
server_activate()
在 Base
中没有实现
在 TCP 中调用
socket.listen
在 UDP 中实现为空函数
Ø
get_request() -> request,
client_address
在 BaseServer 中没有实现
在 TCP 中调用
socket.accept
在 UDP 中调用 socket.recvfrom
Ø
verify_request(request, client_address)
在 Base 中实现为空函数
在 TCP 中没有覆盖
Ø
server_close()
清理 server
所占用的资源,可以被覆盖。
在 Base 中实现为空函数
在TCP中调用
socket.close
在 UDP 中没有覆盖
Ø
process_request(request,
client_address)
在 Base中调用
finish_request,然后 close_request。
在 TCP
中没有覆盖
在 UDP 中没有覆盖
Ø
close_request(request)
清理 request
所占用的资源,可以被覆盖
在 Base 中实现为空函数
在 TCP
中调用 socket.close
在 UDP 中实现为空函数
Ø
handle_error()
在 Base
中打印错误信息。
在 TCP 中没有覆盖
在 UDP 中没有覆盖
向派生类提供的函数:
Ø
finish_request(request, client_address)
在 Base
中通过构造一个 RequestHandlerClass 实例来完成对request 的处理。
在 TCP 中没有覆盖
在 UDP
中没有覆盖
1.3 MixIn结构
为 Base
Server 提供多线程和多进程支持。
1.3.1 ForkingMinxIn提供多进程支持
在列表active_children中保存最大数量为max_children的进程。
在process_request中调用collect_children,检查进程数量是否达到限制。如果进程数量达到限制,需要等待一个进程退出后,才会处理新请求。
在处理新的请求时,通过os.fork创建一个新进程:
1.
父进程
将子进程的oid加入active_children;调用close_request
2.
子进程
调用finish_request,如果发生错误,调用handle_error
1.3.2 ThreadingMixIn提供多线程支持
在process_request中创建新线程,在新线程中调用finish_request和close_request。支持daemon线程。
1.3.3 通过继承使用
通过继承某个MixIn和Server来达到目的。其中MixIn是第一基类,而Server是第二基类。MixIn中的process_request覆盖Server的process_request。
1.4 RequestHandler结构
在BaseRequestHandler中有如下四个函数:
Ø __init__,构造函数
保存request, client_address, server;依次调用 setup, handle, finish。
这是一个Temeplate
Method Pattern,派生类不能覆盖。
如果派生类要提供自己的构造函数,就应该不使用BaseRequestHandler提供的处理模式。
Ø setup,空函数
Ø handle,空函数,处理请求
Ø finish,空函数
在派生类StreamRequestHandler中:
Ø
覆盖setup
根据request(对于TCP来说应该是socket对象)构造read file和write file
这样派生类可以直接使用rfile和wfile进行数据读写
Ø
覆盖finish
对输出文件调用flush;关闭两个文件对象
在派生类DatagramRequestHandler中:
Ø
覆盖setup
将输入流通过StringIO方法封装成read file;构造一个空的输出流StringIO() write
file
Ø
覆盖finish
将输出流中的数据发送到client_address
优点:无论是stream还是datagram方式,通过分别从这两个类派生,都可以直接使用rfile和wfile进行数据读写。
posted on 2009-08-04 16:45
老马驿站 阅读(436)
评论(0) 编辑 收藏 引用 所属分类:
python