标签:
在Python 2.x中, socketserver模块名为SocketServer。该模块可以简化创建服务器的过程。
该模块有四个比较主要的类型,其中常用的是 TCPServer 和 UDPServer。
1. TCPServer
2. UnixStreamServer,类似于TCPServer提供面向数据流的套接字连接,但是旨在UNIX平台上可用;
3. UDPServer
4. UnixDatagramServer,类似于UDPServer提供面向数据报的套接字连接,但是旨在UNIX平台上可用;
这四个类型同步地处理请求,也就是说一个请求没有完成之前是不会处理下一个请求的,这种模式当然不适合生产环境,一个客户端连接就可能拖延所有的执行。所以这个模块还提供了两种支持异步处理的方式:
ForkingMixIn,为每一个客户端请求派生一个新的进程去专门处理;
ThreadingMixIn,为每一个客户端请求派生一个新的线程去专门处理;
首先从高层面介绍一下使用SocketServer模块开发多进程/线程异步服务器的流程:
1. 创建一个合适的服务类型,如,面向TCP连接的多进程服务器: ForkingTCPServer
2. 创建一个请求处理句柄(request handler)类型,这个类型的 handle() 方法(类似于回调函数)将会处理到达的客户端请求连接。
3. 实例化服务器,传入服务器应该绑定的地址和处理请求的句柄类
4. 调用服务器实例的 handle_request() 或 serve_forever() 方法,一次或多次处理客户请求。
1. 构建合适的服务器类型
上文介绍了SocketServer模块提供的几种主要的基本服务类型和两种MixIn类型,就是构造适合需求的多线程/进程服务器的原料。是否使用、如何使用这两个MixIn类型是由程序员决定的,利用的就是Python的多重继承机制,将MixIn类型作为代码库(而不是初始化实例的工具),为实例提供新的方法。
比如,定义一个使用TCP连接的线程式异步服务器类型:
class ForkingTCPServer(FrokingMixIn, TCPServer):
pass
Python的多重继承机制保证了这里只要继承了必要的父类就可以完成目标类型的定义,不需要添加额外的内容。
2. 创建请求处理句柄类
SocketServer模块提供了 BaseRequestHandler 类型用于定制Handler类型,自定义的Handler类型只要继承自 BaseRequestHandler 并覆写它的 handle() 方法即可。handle() 方法定义如何处理客户端的请求,服务器只是封装了socket对象的众多操作流程以及进程、线程等的管理,然后对于每一个客户端请求调用handle() 方法。
BaseRequestHandler类型提供如下的接口,他们都可以根据需要覆写:
(1). BaseRequestHandler.setup()
作用:在handle() 方法之前调用,完成一些初始化的工作,默认的情形下什么也不做。
(2). BaseRequestHandler.handle()
作用:完成所有的对于每个请求的处理工作,默认情况下什么也不做。该方法可以获取一些实例属性,可以在实现时使用: self.request 是客户端的请求,对于TCP而言,该属性是一个套接字对象,对于UDP而言,该属性是一个由字符串和套接字组成的二元组。 self.client_address 是客户端套接字的地址, self.server 则是服务器实例。
StreamRequestHandler 和 DatagramRequestHandler 能够屏蔽 self.request 对TCP和UDP连接的区别,二者都重定义了setup()和finish()方法,提供统一的 self.rfile 和 self.wfile 属性以便从客户端读取数据或向客户端发送数据。
(3). BaseRequestHandler.finish()
作用:在handle() 方法之后调用,完成一些清理的工作,默认的情形下什么也不做。如果setup()方法抛出异常,那么该方法不会被调用。
3. 实例化服务器
实例化服务器时传入服务器需要绑定的地址是必要的,另一方面还应该传入自定义的Handler类型,服务器实例将对每一个客户端连接调用它的 handle() 方法。
例如:
server = ForkingTCPServer((host, port), MyRequestHandler)
4. 调用服务器实例的处理方法
服务器实例的 handle_request() 方法与 serve_forever() 方法分别用于单次处理或一直处理请求,可以直接在脚本中调用这些方法,也可以在新的进程或者线程中调用这些方法,启动服务器:
import threading ... server = ForkingTCPServer((host, port), MyRequestHandler) server_thread = threading.Thread(target = server.serve_forever)
server_thread.start()
补充:
SocketServer中的TCPServer、UDPServer提供的可供使用的属性、方法(实际上都来自于其父类 SocketServer.BaseServer ):
属性:
BaseServer.address_family
内容:服务器套接字对象的地址族,如 socket.AF_INET 、 socket.AF_UNIX 等。
BaseServer.RequestHandlerClass
内容:用户自定义,传给服务器构造函数Handler类型,服务器会为每一个请求创建一个该类型的实例。
BaseServer.server_address
内容:服务器监听的地址,具体的形式依赖于地址族,如AF_INET形式的 (‘127.0.0.1‘, 80) 等。
BaseServer.socket
内容:服务器监听的套接字对象
BaseServer.allow_reuse_address
内容:是否允许地址重用,默认为False,子类可以更改。
BaseServer.request_queue_size
内容:请求队列的长度,一旦等待服务的请求数达到这个限制,后续到来的请求收到“Connection denied”错误,通常该值默认为5,子类可以覆写。
BaseServer.socket_type
内容:服务器所用套接字的类型,如 socket.SOCK_STREAM 和 socket.SOCK_DGRAM 。
BaseServer.timeout
内容:服务器的超时限制,如果是None,那么没有设置超时;如果在指定的时限内 handle_request() 方法没有获得请求,那么将会调用 handle_timeout() 方法。
BaseServer.fileno()
内容:返回服务器所用套接字对象的fd,一种典型的用法是传给 select.select() 方法便于在一个进程中监控多个服务器。
方法:
BaseServer.server_bind()
作用:由实例的构造函数调用,将套接字绑定到目标地址,可以覆写。
BaseServer.server_activate()
作用:由实例的构造函数调用,监听服务器套接字,可以覆写。
BaseServer.handle_request()
作用:处理单个请求,依次调用 get_request() 、 verify_request() 和 process_request() 方法,如果用户自定义的handle()方法抛出异常,则调用 handle_error() 方法,如果超过 self.timeout 秒没有获得请求,调用 handle_timeout() 方法,然后 handle_request() 方法返回。
BaseServer.get_request()
作用:服务器对象的使用者不一定需要直接调用该方法,从套接字接受一个请求。返回一个二元组,首元是新的已经连接的套接字对象,次元是客户端的地址。
BaseServer.verify_request(request, client_address)
作用:服务器对象的使用者不一定需要直接调用该方法。返回一个布尔值,为True时处理请求,为False时拒绝请求,可以通过覆写该方法为服务器实现访问控制。默认的实现总是返回True。
BaseServer.process_request(request, client_address)
作用:该方法体现MixIn的作用,此处可能会创建线程或进程来处理用户的请求,最终都是该方法通过调用 finish_request() 来为每个请求实例化一个用户自定义的Handler实例,然后投到新建的线程或进程中,处理用户的请求。
BaseServer.finish_request()
作用:为每个请求实例化一个用户自定义的Handler实例,并调用其 handle() 方法。
BaseServer.handle_error(request, client_address)
作用:当用户自定义的Handler实例的 handle() 方法抛出异常时,调用该方法。默认的工作是将traceback打印到标准输出,然后继续处理请求。
BaseServer.handle_timeout()
作用:当self.timeout属性规定的超时上限达到时(不是None)还没有等到请求。多进程服务器的默认行为是收集所有已经退出的子进程的状态,多线程服务器默认什么也不做。
BaseServer.serve_forever(poll_interval=0.5)
作用:一直处理请求,直到显式调用 shutdown() 函数,每隔 poll_interval (默认0.5)秒轮询一遍shutdown,该函数无视 self.timeout 。
BaseServer.shutdown()
作用:停止 serve_forever() 循环直到其停止。
标签:
原文地址:http://www.cnblogs.com/Security-Darren/p/4594393.html