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()

客户端代码可以直接用前面的

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__))

 

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
BaseServer类中__init__代码

 

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__代码
分析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这个实例

 

    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()
BaseServer类中serve_forever方法
    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)
BaseServer类中handle_request_noblock方法
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()
ThreadingMixIn类中方法
    def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)
BaseServer中finish_request
#可以看到执行了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()
BaseRequestHandler类__init__

 

整体的主要流程如下

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方法)

 

posted @ 2020-11-23 16:05  泉love水  阅读(308)  评论(0编辑  收藏  举报