从类的继承看socketserver源码

时间:2022-12-25 00:00:54

当我们拿到一份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__()方法,

从类的继承看socketserver源码

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

应该结束了