由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

应该结束了





				
时间: 2024-10-08 10:09:33

由socketserver源码引出的类的继承关系的相关文章

socketserver源码解析和协程版socketserver

来,贴上一段代码让你仰慕一下欧socketserver的魅力,看欧怎么完美实现多并发的魅力 client import socket ip_port = ('127.0.0.1',8009) sk = socket.socket() sk.connect(ip_port) sk.settimeout(5) while True: data = sk.recv(1024) print('receive:',data.decode()) inp = input('please input:') sk

socketserver 源码剖析:

socketserver 源码剖析[有图有真相]: (一).Socketserver 内部流程调用图:        详解: 1.self.RequestHandlerClass() = MyClass() 转换为 执行这个方法 class MyClass(socketserer.BaseRquestHandler). 2. myclass 没有构造方法 __init__( ),从socketserer.BaseRquestHandler 父类 开始找,有构造函数 __init__( ),并且执

用Enterprise Architect从源码自动生成类图

http://blog.csdn.net/zhouyong0/article/details/8281192 /*references:感谢资源分享者.info:简单记录如何通过工具从源码生成类图,便于分析代码结构,对源码阅读挺有用.*/ 看点开源代码学习下,本想找个代码查看方便点的工具,便于理清代码层次,结果发现了Enterprise Architect这一好工具,试用下来还挺方便的.功能上和Rational Rose大致是一类,用处很广,很多我都不懂,知道能画各种UML图,支持的源码语言类型

.NET源码之Page类(二) (转)

.NET源码之Page类(二) 我们在.Net源码之Page类(一) 已经介绍过了初始化与加载阶段了.今天将介绍余下的部分.由于是从源代码上了解生命周期,所以这里会有大量的代码.建议大家看本篇博客的时候最好能够一边对照源代码,最好能够自己调试一遍.希望大家在平时碰到过这方面的问题的,可以留言,能够从源代码这个阶段去剖析问题的实质.         首先我们来回顾一下初始化与加载阶段之间的那个阶段,我们先拿MSDN上对初始化和加载阶段的有2句话描述来看一下: 页初始化阶段:如果当前请求是回发请求,

Struts2 源码分析——Result类实例

本章简言 上一章笔者讲到关于DefaultActionInvocation类执行action的相关知识.我们清楚的知道在执行action类实例之后会相关处理返回的结果.而这章笔者将对处理结果相关的内容进行讲解.笔者叫他们为Result类实例.如果还记得在上一章最后笔者说可以把处理action执行的结果简单的理解处理网页.而且还用红色标识.实际是处理跟表现层有关的内容.而不是页面上的内容.如HTML.即是MVC里面的C到V的内容.当然这还关系到配置文件里面的result元素节点信息.如strtus

细读百度地图点聚合源码(下)---Renderer类解析

上一篇文章分析了ClusterMananger的整体结构和核心算法 细读百度地图点聚合源码(上),此文是接着上一篇来的. 在本文中,我们将学习如何在UI线程中做大量的操作,并且不会造成界面卡顿. 上次我们讲到ClusterManager类中的cluster()方法,调用ClusterTask后台线程处理核心算法,既然有doInBackground()后台任务函数,就会有onPostExecute()函数来处理后台线程返回的结果,这一篇我们就分析怎么处理返回的结果. 那么我们就从返回的结果开始吧!

nginx源码分析--配置信息的继承&合并

这里只讲述http{}模块下的配置: 在ngx_http_block()函数内(这个函数别调用时在ngx_inti_cycle内的ngx_conf_parse函数,这个函数遇到http命令时 回调ngx_http_block,开启http{}配置块的解读工作),针对每一个http模块,调用init_conf之后,有调用了ngx_http_merge_servers().这是为何! 首先明确几点:一个http{}配置块内可以包含多个server{}配置块,每个server{}配置块可以包含多个lo

[Android Studio] Android Studio中查看类的继承关系

转载自:http://blog.csdn.net/hyr83960944/article/details/38098091 查看类的继承关系的快捷键F4,在Android Studio常用快捷键这篇文章中,有写了.今天主要是讲一些关于这个快捷键出来的界面的一些配置,这块功能相对偏冷一些,可能很多人都会用不到.但是关于这些配置,android studio中很多都是类似的. 废话不多说,直接上图,如下图,我选中Activity,然后按F4,右边会出现一个和Activity有继承关系的图. 1.先简

Android Studio中查看类的继承关系

查看类的继承关系的快捷键F4,在Android Studio常用快捷键这篇文章中,有写了.今天主要是讲一些关于这个快捷键出来的界面的一些配置,这块功能相对偏冷一些,可能很多人都会用不到.但是关于这些配置,android studio中很多都是类似的. 废话不多说,直接上图,如下图,我选中Activity,然后按F4,右边会出现一个和Activity有继承关系的图. 1.先简要分析下图中几个元素: 注:这边说第几个图标是从左到右的顺序来数的 第一个图标:显示所有的继承关系,包括父类,子类 第二个图