随笔-167  评论-8  文章-0  trackbacks-0

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 老马驿站 阅读(422) 评论(0)  编辑 收藏 引用 所属分类: python