• 从类的继承看socketserver源码


    当我们拿到一份python源代码,我们要怎么去看呢?

    下面我们以socketserver为例,看下面的一段代码:

     1 #!/usr/bin/env python
     2 # -*- coding: UTF-8 -*-
     3 # Author: ZCX
     4 
     5 import socketserver   #导入socketserver模块
     6 
     7 
     8 class MyServer(socketserver.BaseRequestHandler):  #定义一个类
     9     def handle(self):                   #定义自己的handle方法
    10         pass
    11 
    12 
    13 if __name__ == '__main__':
    14     obj = socketserver.ThreadingTCPServer(('127.0.0.1', 9999), MyServer)   #传递参数
    15     obj.serve_forever()                 #运行

    这段代码的意思是运行一个自定义的服务器,而handle方法是socket传递自定义信息,这里我们暂时不论需要传递什么,当我们拿到这么一段代码,如何深入查看呢?

    从执行的顺序来看,当执行上面的代码时,会执行

     1 obj = socketserver.ThreadingTCPServer(('127.0.0.1', 9999), MyServer) #传递参数 

    这里传了两个参数,一个是
    ('127.0.0.1', 9999),一个是自定义的MyServer类,所以我们就得追寻到底是哪个方法调用了传入的参数呢?


    先来点小知识,类的继承关系是,当子类中没有相应的方法时就会去父类中寻找,当继承多个父类时,子类没有的,依继承顺序,在父类中由左到右依次查询,为了查参,我们先看下ThreadingTCPServer
     1 class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass 


    源码里直接pass了,不过它继承了两个类:
    ThreadingMixIn, TCPServer

    我们先看ThreadingMixIn
    
    
     1 class ThreadingMixIn:
     2     """Mix-in class to handle each request in a new thread."""
     3 
     4     # Decides how threads will act upon termination of the
     5     # main process
     6     daemon_threads = False
     7 
     8     def process_request_thread(self, request, client_address):
     9         """Same as in BaseServer but as a thread.
    10 
    11         In addition, exception handling is done here.
    12 
    13         """
    14         try:
    15             self.finish_request(request, client_address)
    16             self.shutdown_request(request)
    17         except:
    18             self.handle_error(request, client_address)
    19             self.shutdown_request(request)
    20 
    21     def process_request(self, request, client_address):
    22         """Start a new thread to process the request."""
    23         t = threading.Thread(target = self.process_request_thread,
    24                              args = (request, client_address))
    25         t.daemon = self.daemon_threads
    26         t.start()

    有两个方法,但是不是我们想要的啊,FCUK...

    然后只能再去看看TCPServer,

      1 class TCPServer(BaseServer):
      2 
      3     """Base class for various socket-based server classes.
      4 
      5     Defaults to synchronous IP stream (i.e., TCP).
      6 
      7     Methods for the caller:
      8 
      9     - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
     10     - serve_forever(poll_interval=0.5)
     11     - shutdown()
     12     - handle_request()  # if you don't use serve_forever()
     13     - fileno() -> int   # for selector
     14 
     15     Methods that may be overridden:
     16 
     17     - server_bind()
     18     - server_activate()
     19     - get_request() -> request, client_address
     20     - handle_timeout()
     21     - verify_request(request, client_address)
     22     - process_request(request, client_address)
     23     - shutdown_request(request)
     24     - close_request(request)
     25     - handle_error()
     26 
     27     Methods for derived classes:
     28 
     29     - finish_request(request, client_address)
     30 
     31     Class variables that may be overridden by derived classes or
     32     instances:
     33 
     34     - timeout
     35     - address_family
     36     - socket_type
     37     - request_queue_size (only for stream sockets)
     38     - allow_reuse_address
     39 
     40     Instance variables:
     41 
     42     - server_address
     43     - RequestHandlerClass
     44     - socket
     45 
     46     """
     47 
     48     address_family = socket.AF_INET
     49 
     50     socket_type = socket.SOCK_STREAM
     51 
     52     request_queue_size = 5
     53 
     54     allow_reuse_address = False
     55 
     56     def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
     57         """Constructor.  May be extended, do not override."""
     58         BaseServer.__init__(self, server_address, RequestHandlerClass)
     59         self.socket = socket.socket(self.address_family,
     60                                     self.socket_type)
     61         if bind_and_activate:
     62             try:
     63                 self.server_bind()
     64                 self.server_activate()
     65             except:
     66                 self.server_close()
     67                 raise
     68 
     69     def server_bind(self):
     70         """Called by constructor to bind the socket.
     71 
     72         May be overridden.
     73 
     74         """
     75         if self.allow_reuse_address:
     76             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     77         self.socket.bind(self.server_address)
     78         self.server_address = self.socket.getsockname()
     79 
     80     def server_activate(self):
     81         """Called by constructor to activate the server.
     82 
     83         May be overridden.
     84 
     85         """
     86         self.socket.listen(self.request_queue_size)
     87 
     88     def server_close(self):
     89         """Called to clean-up the server.
     90 
     91         May be overridden.
     92 
     93         """
     94         self.socket.close()
     95 
     96     def fileno(self):
     97         """Return socket file number.
     98 
     99         Interface required by selector.
    100 
    101         """
    102         return self.socket.fileno()
    103 
    104     def get_request(self):
    105         """Get the request and client address from the socket.
    106 
    107         May be overridden.
    108 
    109         """
    110         return self.socket.accept()
    111 
    112     def shutdown_request(self, request):
    113         """Called to shutdown and close an individual request."""
    114         try:
    115             #explicitly shutdown.  socket.close() merely releases
    116             #the socket and waits for GC to perform the actual close.
    117             request.shutdown(socket.SHUT_WR)
    118         except OSError:
    119             pass #some platforms may raise ENOTCONN here
    120         self.close_request(request)
    121 
    122     def close_request(self, request):
    123         """Called to clean up an individual request."""
    124         request.close()

    我们看到它接收到了一个server_address,和RequestHandlerClass,所以obj接收的参数到了这里,

    我们再看它的接收方法,重建了__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)
            if bind_and_activate:
                try:
                    self.server_bind()
                    self.server_activate()
                except:
                    self.server_close()
                    raise

    那么

    BaseServer.__init__(self, server_address, RequestHandlerClass)接收是要从哪里看呢?server_address, RequestHandlerClass
    紧接着我看到,重定义的__init__()方法执行了BaseServer.__init__()的方法,那么实际上就是去
    BaseServer,执行了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)

    接着我们再去看
    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
    self.__is_shut_down = threading.Event()
    self.__shutdown_request = False


    从这里看再从整体上看可以看出来,self.RequestHandlerClass其实就是我们最初定义的类=>MyServer.
    到这里应该没有什么大问题,server_address就是我们传出的IP加端口
    然后我们再看下一句
    obj.serve_forever()  

    执行了serve_forever()方法

     1     def serve_forever(self, poll_interval=0.5):
     2         """Handle one request at a time until shutdown.
     3 
     4         Polls for shutdown every poll_interval seconds. Ignores
     5         self.timeout. If you need to do periodic tasks, do them in
     6         another thread.
     7         """
     8         self.__is_shut_down.clear()
     9         try:
    10             # XXX: Consider using another file descriptor or connecting to the
    11             # socket to wake this up instead of polling. Polling reduces our
    12             # responsiveness to a shutdown request and wastes cpu at all other
    13             # times.
    14             with _ServerSelector() as selector:
    15                 selector.register(self, selectors.EVENT_READ)
    16 
    17                 while not self.__shutdown_request:
    18                     ready = selector.select(poll_interval)
    19                     if ready:
    20                         self._handle_request_noblock()
    21 
    22                     self.service_actions()
    23         finally:
    24             self.__shutdown_request = False
    25             self.__is_shut_down.set()

    看源代码可以看到,

    if ready:

      self._handle_request_noblock()

    也就是说,成功的话执行的就是self._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)

    第一个try是接收客户端的数据,第二个try是处理的方法,那么我们看到执行了

    self.process_request()方法

    反回看BaseSever的代码,代码里就定义了self.process_request()方法,那么实际是执行这个方法么?

     我们回头看,类的继承关系是,当子类中没有相应的方法时就会去父类中寻找,当继承多个父类时,子类没有的,依继承顺序,在父类中由左到右依次查询
    ThreadingTCPServer
     1 class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass 

     我们从这里可以看出,得先看下

    ThreadingMixIn
    我记得里面也有一个self.process_request()方法哦

     1 class ThreadingMixIn:
     2     """Mix-in class to handle each request in a new thread."""
     3 
     4     # Decides how threads will act upon termination of the
     5     # main process
     6     daemon_threads = False
     7 
     8     def process_request_thread(self, request, client_address):
     9         """Same as in BaseServer but as a thread.
    10 
    11         In addition, exception handling is done here.
    12 
    13         """
    14         try:
    15             self.finish_request(request, client_address)
    16             self.shutdown_request(request)
    17         except:
    18             self.handle_error(request, client_address)
    19             self.shutdown_request(request)
    20 
    21     def process_request(self, request, client_address):
    22         """Start a new thread to process the request."""
    23         t = threading.Thread(target = self.process_request_thread,
    24                              args = (request, client_address))
    25         t.daemon = self.daemon_threads
    26         t.start()

    看到了吧,哈哈,这下再也不会怕看源代码了吧

    最后两步,从上面一看就知道执行

    process_request_thread

    最后是

    self.finish_request

    应该结束了











  • 相关阅读:
    list浅析
    C#尝试读取或写入受保护的内存。这通常指示其他内存已损坏(catch不起作用)
    浅析C#线程同步事件-WaitHandle
    C#操作xml方法1
    C#简单的操作csv文件
    C#的int类型?,??,~的意思,string类型空值赋值
    将多个exc表格汇总于一个表格中
    C#禁止双击标题栏等操作
    c#泛型
    c#session
  • 原文地址:https://www.cnblogs.com/zcx-python/p/5663840.html
Copyright © 2020-2023  润新知