本篇socketserver源码阅读主要目的是熟悉Python中的继承模式
示例代码
1 | import socketserver |
阅读入口
1 | obj = socketserver.ThreadingTCPServer(('127.0.0.1', 1559), MyClass) |
从以上这一行代码中可以看出,执行了ThreadingTCPServer
类中的__init__
方法(实例化了这个类的对象,就从这里为入口点来阅读)
ThreadingTCPServer类图
step by step
step 1
首先,从实例化ThreadingTCPServer
这个类的对象可以得知,是执行了这个对象的__init__
构造方法,但是我们查看这个类的源码发现,只有一个pass
1 | class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass |
但是这个类继承了两个父类,那么必然是执行了父类的__init__
方法。在查找父类__init__
方法的时候,首先从左边的父类开始查找
step 2
ThreadingTCPServer
继承的第一个父类中ThreadingMixIn
,没有找到__init__
构造方法,接着,Python会去ThreadingTCPServer
继承的第二个父类总去查找
step 3
在ThreadingTCPServer
继承的第二个父类TCPServer
找到了__init__
构造方法并执行
1 | def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): |
在这段构造方法中,前三个参数对应了示例代码中,创建ThreadingTCPServer
对象时的三个参数
1 | obj = socketserver.ThreadingTCPServer(('127.0.0.1', 1559), MyClass) |
1 | def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): |
- self —> obj
- server_address —> (‘127.0.0.1’, 1559)
- RequestHandlerClass —> MyClass
在TCPServer
的构造方法拿到这几个参数之后,紧接着又调用了父类的__init__
构造方法
step 3.1
在TCPServer
的父类BaseServer
中,__init__
构造方法执行了以下内容
1 | def __init__(self, server_address, RequestHandlerClass): |
创建了两个公有变量和两个私有变量,并且
- RequestHandlerClass —> MyClass
step 4
TCPServer
在执行完父类的构造方法封装了四个字段后,继续向下执行
1 | self.socket = socket.socket(self.address_family, |
创建了一个socket对象
1 | if bind_and_activate: |
step 4.1
1 | def server_bind(self): |
绑定了IP和端口号,self.server_address
的值是在执行父类BaseServer
的构造方法时创建的
step 4.2
1 | def server_activate(self): |
监听socket
至此,TCPServer
中的__init__
构造方法执行完毕,构造方法执行完毕,就意味着示例代码中的
1 | obj = socketserver.ThreadingTCPServer(('127.0.0.1', 1559), MyClass) |
这一句就执行完毕了
step 5
接下来测试代码走到第10行
1 | obj.serve_forever() |
ThreadingTCPServer
首先在自己的代码块中查找,没有
根据继承的规则,再去左边的父类ThreadingMixIn
中查找,没有
之后再去右边的父类TCPServer
中查找,没有
最后在TCPServer
的父类BaseServer
中找到了serve_forever
方法
1 | def serve_forever(self, poll_interval=0.5): |
step 5.1
1 | ready = selector.select(poll_interval) |
IO多路复用,这里没有使用self来调,而是使用selector对象来调select方法
1 | def select(self, timeout=None): |
step 5.2
在有客户端连接进来的时候,ready就有有值,为真,会执行self._handle_request_noblock
方法
因为是self.来调用的,根据继承规则,就要回到最开始的类中,再逐级向上查找,所以回到ThreadingTCPServer
中查找,没有
根据继承的规则,再去左边的父类ThreadingMixIn
中查找,没有
之后再去右边的父类TCPServer
中查找,没有
最后在TCPServer
的父类BaseServer
中找到了_handle_request_noblock
方法
1 | def _handle_request_noblock(self): |
step 5.3
1 | request, client_address = self.get_request() |
根据类图查找,在TCPServer类中
1 | def get_request(self): |
接受客户端连接请求
step 6
在_handle_request_noblock
方法中又执行了self.process_request
方法
回到ThreadingTCPServer
中查找,没有
根据继承的规则,在左边的父类ThreadingMixIn
中找到该方法
1 | def process_request(self, request, client_address): |
在这个方法中,使用了多线程去执行self.process_request_thread
方法
1 | t = threading.Thread(target = self.process_request_thread, |
使用了self调用,还是要从头查找
step 7
在ThreadingMixIn
类中找到
1 | def process_request_thread(self, request, client_address): |
这个方法应该是用来接收客户端发来的请求以及给客户端发送消息
step 8
1 | self.finish_request(request, client_address) |
根据类图,在BaseServer
中找到
1 | def finish_request(self, request, client_address): |
在step3
中已经封装了RequestHandlerClass = MyClass
相当于执行了MyClass的构造方法
1 | MyClass(request, client_address, self) |
step 9
MyClass中没有定义构造方法,在MyClass继承的父类socketserver.BaseRequestHandler
中查找,找到了构造方法
1 | def __init__(self, request, client_address, server): |
执行了self.handle()
step 10
执行self.handle()
方法时,就会执行MyClass中定义的handle
方法
在示例代码中,我们已经自定义了一个方法去实现与客户端的交互,