python学习之socketserver实现并发
前面学习了socket的相关知识,但是只能处理单线程的,当然我们也可以使用python多线程模块实现多线程并发,python中socketserver模块实现了并发相关操作,本文主要记录一下学习过程。
服务端代码如下: #1、自定义一个类 #2、在类中重写handle方法(该方法中实现自己业务逻辑) import socketserver class Myserver(socketserver.BaseRequestHandler): def handle(self): print('conn is: ', self.request) # conn print('addr is: ', self.client_address) # addr while True: try: data=self.request.recv(1024) if not data:break print('收到客户端的消息是', data, self.client_address) # 发消息 self.request.sendall(data.upper()) except Exception as e: print(e) break if __name__ == '__main__': s = socketserver.ThreadingTCPServer(('127.0.0.1', 9090), Myserver)#实例化,会执行__init__方法(按照查找顺序去查找), s.serve_forever()
客户端代码可以直接用前面的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import socket sk = socket.socket() addr = ('127.0.0.1',9090) sk.connect(addr) while True: inp = input('>>>') if inp == 'q': break sk.send(bytes(inp,'utf8')) data = sk.recv(1024) print(str(data,'utf8')) sk.close()
服务端socketserver 内部主要流程和相关源码分析如下:
1、s = socketserver.ThreadingTCPServer(('127.0.0.1', 9090), Myserver)进行了实例化
ThreadingTCPServer(('127.0.0.1', 9090), Myserver)实例化,会执行__init__方法(按照查找顺序去查找),执行TCPServer类中__init__方法(TCPServer类中调用了BaseServer类中__init__方法(BaseServer.__init__))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def __init__(self, server_address, RequestHandlerClass): """Constructor. May be extended, do not override.""" self.server_address = server_address self.RequestHandlerClass = RequestHandlerClass#就是我们自己定义的Myserver类 self.__is_shut_down = threading.Event() self.__shutdown_request = False
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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)#此处看到熟悉的代码,即创建了socket对象 if bind_and_activate: try: self.server_bind() self.server_activate() except: self.server_close() raise
分析TCPServer类中__init__代码可以看到做了如下操作 1、调用了BaseServer类中__init__方法(BaseServer类中__init__中主要就是进行了一些属性封装操作) 2、创建socket对象 3、执行server_bind和server_activate方法(也是按照类继承的查找顺序去查找执行哪个类中的该方法,此时执行的就是TCPServer类中这两个方法) 4、server_bind中主要就是self.socket.bind(self.server_address)即bind ip和port 5、server_activate中就是self.socket.listen(self.request_queue_size)即listen
由上述分析可知s = socketserver.ThreadingTCPServer(('127.0.0.1', 9090), Myserver)执行后主要就是创建socket对象、bind、listen,并且把我们自定义的类赋值给self.RequestHandlerClass
2、执行s.serve_forever()
s.serve_forever()即实例调用类方法(分析可知执行的是BaseServer类中serve_forever方法),可以看到serve_forever中调用self._handle_request_noblock()方法,self._handle_request_noblock()
中调用self.process_request(request, client_address)方法(按照查找顺序查找执行的是哪个类中self.process_request),分析可知,执行的是ThreadingMixIn类中的process_request方法,self.process_request中
执行self.process_request_thread方法,self.process_request_thread执行self.finish_request(request, client_address)(按照查找顺序去执行,可以看到执行的是BaseServer中finish_request),self.finish_request执行
self.RequestHandlerClass(request, client_address, self),可以看到就是执行我们最初自定义的那个类,此时就是对Myserver类进行了实例化,也会先执行__init__方法,通过分析可知执行的是Myserver
继承的类BaseRequestHandler中__init__方法,分析可以看到执行了handle()(就是我们自己定义的Myserver类中的handle方法,进入到我们自定义的逻辑)
注意:通过self去调用各种类中的方法时,类继承时查找方法的顺序,在该分析中self永远代指s这个实例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def serve_forever(self, poll_interval=0.5): """Handle one request at a time until shutdown. Polls for shutdown every poll_interval seconds. Ignores self.timeout. If you need to do periodic tasks, do them in another thread. """ self.__is_shut_down.clear() try: # XXX: Consider using another file descriptor or connecting to the # socket to wake this up instead of polling. Polling reduces our # responsiveness to a shutdown request and wastes cpu at all other # times. with _ServerSelector() as selector: selector.register(self, selectors.EVENT_READ) 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()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 Exception: self.handle_error(request, client_address) self.shutdown_request(request) except: self.shutdown_request(request) raise else: self.shutdown_request(request)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class ThreadingMixIn: """Mix-in class to handle each request in a new thread.""" # Decides how threads will act upon termination of the # main process daemon_threads = False def process_request_thread(self, request, client_address): """Same as in BaseServer but as a thread. In addition, exception handling is done here. """ try: self.finish_request(request, client_address) except Exception: self.handle_error(request, client_address) finally: self.shutdown_request(request) def process_request(self, request, client_address): """Start a new thread to process the request.""" t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads t.start()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def finish_request(self, request, client_address): """Finish one request by instantiating RequestHandlerClass.""" self.RequestHandlerClass(request, client_address, self)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#可以看到执行了handle(),就是我们自己定义的Myserver类中的handle方法 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()
整体的主要流程如下
1、执行 TCPServer.init 方法,创建服务端Socket对象并绑定 IP 和 端口 2、执行 BaseServer.init 方法,将我们自定义的类赋值给self.RequestHandlerClass 3、执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 有客户端请求到来时 1、执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求 2、执行 ThreadingMixIn.process_request_thread 方法 3、执行 BaseServer.finish_request 方法(执行 self.RequestHandlerClass() ,即实例化会执行__init__,构造方法中执行了self.handle()此时执行的就是我们自定义类中的handle方法)