Python的socket模块源码中的一些实现要点分析
|
BaseServer 和 BaseRequestHandler 改模块的主要几个Server关系如下:
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
BaseServer 分析 init 初始化:
def __init__(self,server_address,RequestHandlerClass):
"""Constructor. May be extended,do not override."""
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
__init__源码很简单。主要作用是创建server对象,并初始化server地址和处理请求的class。熟悉socket编程应该很清楚,server_address是一个包含主机和端口的元组。 serve_forever
def serve_forever(self,poll_interval=0.5):
self.__is_shut_down.clear()
try:
while not self.__shutdown_request:
r,w,e = _eintr_retry(select.select,[self],[],poll_interval)
if self in r:
self._handle_request_noblock()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
serve_forever接受一个参数poll_interval,用于表示select轮询的时间。然后进入一个无限循环,调用select方式进行网络IO的监听。 如果select函数返回,表示有IO连接或数据,那么将会调用_handle_request_noblock方法。
_handle_request_noblock
def _handle_request_noblock(self):
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.shutdown_request(request)
_handle_request_noblock方法即开始处理一个请求,并且是非阻塞。该方法通过get_request方法获取连接,具体的实现在其子类。一旦得到了连接,调用verify_request方法验证请求。验证通过,即调用process_request处理请求。如果中途出现错误,则调用handle_error处理错误,以及shutdown_request结束连接。
verify_request
def verify_request(self,request,client_address):
return True
该方法对request进行验证,通常会被子类重写。简单的返回True即可,然后进入process_request方法处理请求。
process_request
def process_request(self,client_address):
self.finish_request(request,client_address)
self.shutdown_request(request)
process_request方法是mixin的入口,MixIn子类通过重写该方法,进行多线程或多进程的配置。调用finish_request完成请求的处理,同时调用shutdown_request结束请求。
finish_request
def finish_request(self,client_address):
self.RequestHandlerClass(request,client_address,self)
finish_request方法将会处理完毕请求。创建requestHandler对象,并通过requestHandler做具体的处理。 BaseRequestHandler 分析
def __init__(self,server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()
该类会处理每一个请求。初始化对象的时候,设置请求request对象。然后调用setup方法,子类会重写该方法,用于处理socket连接。接下来的将是handler和finish方法。所有对请求的处理,都可以重写handler方法。 至此,整个Python提供的Server方式即介绍完毕。总结一下,构建一个网络服务,需要一个BaseServer用于处理网络IO,同时在内部创建requestHandler对象,对所有具体的请求做处理。 BaseServer - BaseRequestHandler
__init__(server_address,RequestHandlerClass):
BaseServer.server_address
BaseServer.RequestHandlerClass
serve_forever():
select()
BaseServer._handle_request_noblock()
BaseServer.get_request() -> request,client_addres
BaseServer.verify_request()
BaseServer.process_request()
BaseServer.process_request()
BaseServer.finish_request()
BaseServer.RequestHandlerClass()
BaseRequestHandler.__init__(request)
BaseRequestHandler.request
BaseRequestHandler.client_address = client_address
BaseRequestHandler.setup()
BaseRequestHandler.handle()
BaseServer.shutdown_request()
BaseServer.close_request()
BaseServer.shutdown_request()
BaseServer.close_request()
BaseServer 和 BaseRequestHandler是网络处理的两个基类。实际应用中,网络操作更多是使用 TCP 或 HTTP 协议。SocketServer.py 也提供了更高级的TCP、UDP封装。下面就来看下关于TCP方面的网络模块(UDP和TCP的在代码组织上差别不是特别大,暂且忽略)。 TCPServer
def __init__(self,RequestHandlerClass,bind_and_activate=True):
BaseServer.__init__(self,RequestHandlerClass)
self.socket = socket.socket(self.address_family,self.socket_type)
if bind_and_activate:
self.server_bind()
self.server_activate()
__init__ 方法通过 socket模块创建了socket对象,然后进行调用server_bind和server_activate。
server_bind
def server_bind(self):
if self.allow_reuse_address:
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.socket.bind(self.server_address)
self.server_address = self.socket.getsockname()
server_bind 方法进行socket对象的bind操作,以及设置socket相关属性,如网络地址的复用。 server_activate def server_activate(self): self.socket.listen(self.request_queue_size) server_activate 方法也比较简单,添加socket对象的listen。 get_request def get_request(self): """Get the request and client address from the socket. """ return self.socket.accept() get_request方法是在BaseServer基类中的_handle_request_noblock中调用,从那里里传入套接字对象获取的连接信息。如果是UDPServer,这里获取的就是UDP连接。 此外,TCPServer还提供了一个 fileno 方法,提供给基类的select调用返回文件描述符。 StreamRequestHandler setup方法:
def setup(self):
self.connection = self.request
if self.timeout is not None:
self.connection.settimeout(self.timeout)
if self.disable_nagle_algorithm:
self.connection.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,True)
self.rfile = self.connection.makefile('rb',self.rbufsize)
self.wfile = self.connection.makefile('wb',self.wbufsize)
setup判断了是否使用nagle算法。然后设置对应的连接属性。最重要的就是创建了一个可读(rfile)和一个可写(wfile)的“文件”对象,他们实际上并不是创建了文件,而是封装了读取数据和发送数据的操作,抽象成为对文件的操作。可以理解为 self.rfile 就是读取客户端数据的对象,它有一些方法可以读取数据。self.wfile则是用来发送数据给客户端的对象。后面的操作,客户端数据到来会被写入缓冲区可读,需要向客户端发送数据的时候,只需要向可写的文件中write数据即可。 实现TCP服务需要使用TCPServer和StreamRequestHandler共同协作。大致函数调用流程如下,函数调用用括号表示,赋值不带括号,没有类前缀的表示系统调用: (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
