SocketServer 中非常重要的两个基类就是:BaseServer 和 BaseRequestHandler
在SocketServer 中也提供了对TCP以及UDP的高级封装,这次我们主要通过分析关于TCP的处理逻辑来对SocketServer模块进行一个很好的理解和学习
TCPServer
TCPServer 继承了BaseServer,初始化的时候,进行了socket套接字的创建。
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): """Constructor. May be extended, do not override.""" BaseServer.__init__(self, server_address, RequestHandlerClass) self.socket = socket.socket(self.address_family, self.socket_type) if bind_and_activate: try: self.server_bind() self.server_activate() except: self.server_close() raise
在这里我们看到了我们非常熟悉的关于socket的创建的内容:
self.socket = socket.socket(self.address_family, self.socket_type)
通过socket模块创建了socket对象,接着调用了server_bind和server_activate
server_bind
源码内容如下:
def server_bind(self): """Called by constructor to bind the socket. May be overridden. """ 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()
这里我们看到了非常熟悉的操作socket.bind方法,以及设置了socket的相关属性
server_activate
源码内容如下:
def server_activate(self): """Called by constructor to activate the server. May be overridden. """ self.socket.listen(self.request_queue_size)
同样的这里的调用也非常简单就是执行了socket.listen
get_request
在TCPServer类中我们还看到了get_request方法,源码内容如下:
def get_request(self): """Get the request and client address from the socket. May be overridden. """ return self.socket.accept()
这个的调用其实我们可以在BaseServer这个基类中看到,我们之前看过关于BaseServer中这个基类的源码
我们可以从我们调用BaseServer基类中的serve_forever方法查看,这里是调用了_handle_request_noblock方法,我继续查看_handle_request_noblock这个源码
def _handle_request_noblock(self): """Handle one request, without blocking. I assume that selector.select() has returned that the socket is readable before this function was called, so there should be no risk of blocking in get_request(). """ try: request, client_address = self.get_request() except OSError: 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) else: self.shutdown_request(request)
可以看到这里最后是调用了process_request来处理请求,继续查看源码:
def process_request(self, request, client_address): """Call finish_request. Overridden by ForkingMixIn and ThreadingMixIn. """ self.finish_request(request, client_address) self.shutdown_request(request) def finish_request(self, request, client_address): """Finish one request by instantiating RequestHandlerClass.""" self.RequestHandlerClass(request, client_address, self)
从上面的代码我们可以到最后是在finish_request中实例化了RequestHandlerClass
我们 这个时候查看一下BaseRequestHandler这个基类的源码如下:
class BaseRequestHandler: """Base class for request handler classes. This class is instantiated for each request to be handled. The constructor sets the instance variables request, client_address and server, and then calls the handle() method. To implement a specific service, all you need to do is to derive a class which defines a handle() method. The handle() method can find the request as self.request, the client address as self.client_address, and the server (in case it needs access to per-server information) as self.server. Since a separate instance is created for each request, the handle() method can define other arbitrary instance variables. """ def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish() def setup(self): pass def handle(self): pass def finish(self): pass
在初始化函数里我们看到了调用setup()方法,这setup在StreamRequestHandler会被重写
StreamRequestHandler
TCPServer实现了使用tcp套接字的网络服务,Handler方面则是对应的StreamRequestHandler。它继承了BaseRequestHandler。基类的setup方法和finish方法被它重写,用于通过连接实现缓存文件的读写操作。
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)
这里主要设置了对应连接的属性,其中创建了两个对象非常重要:
一个可读(rfile)和一个可写(wfile)的“文件”对象
但是实际并不是创建了文件,而是封装了读取数据和发送数据的操作,抽象成了对文件的操作
可以理解:
self.rfile 就是读取客户端数据的对象,它有一些方法可以读取数据。self.wfile则是用来发送数据给客户端的对象。
整理流程(TCP)
实现TCP服务需要使用TCPServer和StreamRequestHandler共同协作