解读socketserver之Tcpserver
Posted 看雪。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解读socketserver之Tcpserver相关的知识,希望对你有一定的参考价值。
从代码开始,慢慢解开socketserver面纱:
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "localhost", 9999 with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server: server.serve_forever()
我们通过socketserver.TCPServer实例化对象server,那么此时应用调用类的__init__方法,前往Tcpserver类看看:
class TCPServer(BaseServer): address_family = socket.AF_INET socket_type = socket.SOCK_STREAM request_queue_size = 5 allow_reuse_address = False def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): BaseServer.__init__(self, server_address, RequestHandlerClass)# self.socket = socket.socket(self.address_family,self.socket_type) # 创建套接字对象 if bind_and_activate: try: self.server_bind() #绑定端口和IP self.server_activate() # 监听端口 except: self.server_close() raise
看到Tcpserver的__init__方法,完成了以下几件事:
创建套接字,绑定端口和IP,并监听
将端口、IP和我们创建类传递到Baseserver类中;
此时,对象的初始化工作并没有完成,接着,我们要进入baseserver类,看看该类下的__init__完成了什么工作:
class BaseServer: timeout = None def __init__(self, server_address, RequestHandlerClass): self.server_address = server_address #将端口和IP暂存 self.RequestHandlerClass = RequestHandlerClass #暂存我们创建的类 self.__is_shut_down = threading.Event() # 创建event对象
到此,对象的初始化工作完成。然后是调用serve_forever()方法,开始不断循环监听。下面,我们来看看,这个server_forever实现
注意:我们要清楚一点,我们在找這个方法在哪里的时候,一定要按照顺序去找,也就是说,我们先得从子类开始找,如果子类不存在,就去其父类找。下面我们就遵循這个原则来找找看。
先来看看父类Tcpserver:
class TCPServer(BaseServer):def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): def server_bind(self): def server_activate(self): def server_close(self): def fileno(self): def get_request(self): def shutdown_request(self, request): def close_request(self, request):
我们发现,没有server_forever方法,好,我去其继承的父类BaseServer类看看:
class BaseServer:def __init__(self, server_address, RequestHandlerClass): def server_activate(self): def serve_forever(self, poll_interval=0.5): def shutdown(self): def service_actions(self): def handle_request(self): def _handle_request_noblock(self): def handle_timeout(self): def verify_request(self, request, client_address): def process_request(self, request, client_address): def server_close(self): def finish_request(self, request, client_address): def shutdown_request(self, request): def close_request(self, request): def handle_error(self, request, client_address): def __enter__(self): def __exit__(self, *args):
我们发现server_forever()果然在這个类中,现在,我们的目标是:找到在什么地方调用我们自己写的handle方法。
在我们找到的server_forever()方法中,
def serve_forever(self, poll_interval=0.5): self.__is_shut_down.clear() try: with _ServerSelector() as selector: selector.register(self, selectors.EVENT_READ)#原来底层是用epoll来实现不断循环监听 while not self.__shutdown_request: ready = selector.select(poll_interval) #有新的链接进来 if ready: self._handle_request_noblock() # 这里应该是处理新的链接 self.service_actions() finally: self.__shutdown_request = False self.__is_shut_down.set()
好,我大致找到了链接的处理入口,我们跟进去,继续寻找:
def _handle_request_noblock(self): 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 Exception: self.handle_error(request, client_address) self.shutdown_request(request) except: self.shutdown_request(request) raise else: self.shutdown_request(request)
到源码中,我们找到该函数,现在,只看我划线的部分。其他部分都是针对异常的处理,如果没有异常,其他都是不会执行的,所以,其他的异常处理,我们先暂时不看。
我们发现,如果有链接,最后会交给process_request(),现在,我们继续跟进:
def process_request(self, request, client_address): self.finish_request(request, client_address) self.shutdown_request(request)
看到這个函数执行了两个函数,我们先到第一个finish_requset()里面看看,
def finish_request(self, request, client_address): self.RequestHandlerClass(request, client_address, self)
执行了RequestHandlerClass(request, client_address, self),這个是啥??还记得最开始我们传进来的类保存在哪呢?没错,就是RequestHandlerClass里面,现在这里才开始实例化這个类,也就是说,在这里开始调用我们自己的类了。既然是调用我们自己的类,那么必然要实例化,我们先回到自己创建的类,找找__init__方法。
class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.sendall(self.data.upper())
自己类没有写__init__方法,那么我去它继承的BaseRequestHandler()下面找找看:
class BaseRequestHandler: def __init__(self, request, client_address, server): self.request = request # 接受传进来的请求链接 self.client_address = client_address # 客户端的ip/端口 self.server = server # self.setup() try: self.handle() finally: self.finish() def setup(self): pass def handle(self): pass def finish(self): pass
我们来看看,它继承类实例化完成了哪些操作:
调用handle()方法,我们发现,在这个类中也有一个handle()方法,那么这里调用时调用自己写的还是這个类中的呢?
当然是调用我们自己写!
至此,我们完成了一次链接的完整过程!
以上是关于解读socketserver之Tcpserver的主要内容,如果未能解决你的问题,请参考以下文章
Python 的 SocketServer 中的 TCPServer + BaseRequestHandler 是不是在每次调用 handle() 后关闭套接字?