当我们拿到一份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
应该结束了