您的位置:首页 > 编程语言

代码阅读 - SocketServer.py

2009-01-05 09:47 357 查看

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进行数据读写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: