从类的继承看socketserver源码

时间:2022-09-06 20:42:56

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

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

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

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

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

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

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

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

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

我们先看ThreadingMixIn

 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)
self.shutdown_request(request)
except:
self.handle_error(request, client_address)
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()

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

然后只能再去看看TCPServer,

 class TCPServer(BaseServer):

     """Base class for various socket-based server classes.

     Defaults to synchronous IP stream (i.e., TCP).

     Methods for the caller:

     - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
- serve_forever(poll_interval=0.5)
- shutdown()
- handle_request() # if you don't use serve_forever()
- fileno() -> int # for selector Methods that may be overridden: - server_bind()
- server_activate()
- get_request() -> request, client_address
- handle_timeout()
- verify_request(request, client_address)
- process_request(request, client_address)
- shutdown_request(request)
- close_request(request)
- handle_error() Methods for derived classes: - finish_request(request, client_address) Class variables that may be overridden by derived classes or
instances: - timeout
- address_family
- socket_type
- request_queue_size (only for stream sockets)
- allow_reuse_address Instance variables: - server_address
- RequestHandlerClass
- socket """ address_family = socket.AF_INET socket_type = socket.SOCK_STREAM request_queue_size = 5 allow_reuse_address = False 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 def server_bind(self):
"""Called by constructor to bind the socket. May be overridden. """
if self.allow_reuse_address:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
self.server_address = self.socket.getsockname() def server_activate(self):
"""Called by constructor to activate the server. May be overridden. """
self.socket.listen(self.request_queue_size) def server_close(self):
"""Called to clean-up the server. May be overridden. """
self.socket.close() def fileno(self):
"""Return socket file number. Interface required by selector. """
return self.socket.fileno() def get_request(self):
"""Get the request and client address from the socket. May be overridden. """
return self.socket.accept() def shutdown_request(self, request):
"""Called to shutdown and close an individual request."""
try:
#explicitly shutdown. socket.close() merely releases
#the socket and waits for GC to perform the actual close.
request.shutdown(socket.SHUT_WR)
except OSError:
pass #some platforms may raise ENOTCONN here
self.close_request(request) def close_request(self, request):
"""Called to clean up an individual request."""
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()方法
     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()

看源代码可以看到,

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()方法哦
 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)
self.shutdown_request(request)
except:
self.handle_error(request, client_address)
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()

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

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

process_request_thread

最后是
self.finish_request

应该结束了






从类的继承看socketserver源码的更多相关文章

  1. 解读python中SocketServer源码

    在看SocketServer源码之前,先看一个例子: class Base(object): def __init__(self, name): self.name = name self.Testf ...

  2. python_way day10 python和其他语言的作用域 、 python2.7多继承和3.5多继承的区别 、 socket 和 socketserver源码(支持并发处理socket,多进程,多线程)

    python_way day10 1.python的作用域和其他语言的作用域 2.python2.7多继承和3.5多继承的区别 3.socket和socketserver源码(并发处理socket) ...

  3. Python之socketserver源码分析

    一.socketserver简介 socketserver是一个创建服务器的框架,封装了许多功能用来处理来自客户端的请求,简化了自己写服务端代码.比如说对于基本的套接字服务器(socket-based ...

  4. SocketServer源码学习(一)

    SocketServer其实是对socket更高级的封装正如官网上说的:The socketserver module simplifies the task of writing network s ...

  5. 解读socketserver源码

    解读python中SocketServer源码 再看继承 真正的大餐来之前,还是来点儿开胃菜!回顾一下关于类的继承的知识:    我们先看上面的代码,这是一个简单的类继承,我们可以看到父类Base和子 ...

  6. 文件上传下载、socketserver(并发)、解读socketserver源码

    1.文件上传/下载 学习了socket套接字,我们现在可以写一个文件上传/下载的程序,如下示例: 分析上边代码,我们发现,client发送上传文件相关信息的字典序列化之后,server又给client ...

  7. socketserver源码解析和协程版socketserver

    来,贴上一段代码让你仰慕一下欧socketserver的魅力,看欧怎么完美实现多并发的魅力 client import socket ip_port = ('127.0.0.1',8009) sk = ...

  8. socketserver 源码剖析:

    socketserver 源码剖析[有图有真相]: (一).Socketserver 内部流程调用图:        详解:  1.self.RequestHandlerClass() = MyCla ...

  9. python day 15: IO多路复用,socketserver源码培析,

    目录 python day 15 1. IO多路复用 2. socketserver源码分析 python day 15 2019/10/20 学习资料来自老男孩教育 1. IO多路复用 ''' I/ ...

随机推荐

  1. 创建table并实现ID自增长

    ① create table p_user( id               number(10) not null primary key, name             varchar2(3 ...

  2. Easy Tag Write(3.3)

    package skyseraph.android.util; /** * @Title : Constant.java * @Package : tcl.nfc.tv.util * @ClassNa ...

  3. srand()以及rand()函数用法

    srand()就是给rand()提供种子seed 如果srand每次输入的数值是一样的,那么每次运行产生的随机数也是一样的, srand(n) for(10) rand()也就是说,以一个固定的数值作 ...

  4. JavaScript开发规范要求

    http://www.cnblogs.com/webflash/archive/2010/06/11/1756255.html 作为一名开发人员(WEB前端JavaScript开发),不规范的开发不仅 ...

  5. Accessing the Deep Web: A Survey

    http://www.inf.ufsc.br/~ronaldo/deepWeb/querying/Chang-dwsurvey-cacm07.pdf

  6. 文件和文件夹权限-Win7公共盘中出现大量临时文件

    公司中有一个文件服务器,给不同部门和员工设置了不同的权限,最近有员工(没有修改权限,有读取及执行,读取,写入)反映在公共盘上修改文件的时候会产生大量的临时文件,添加上修改权限之后就可以了,然后被同事问 ...

  7. vue-cli 自定义指令directive 添加验证滑块

    vue项目注册登录页面遇到了一个需要滑块的功能,网上看了很多插件发现都不太好用,于是自己写了一个插件供大家参考: 用的是vue的自定义指令direcive,只需要在需要的组件里放入对应的标签嵌套即可: ...

  8. Java语言基础之方法的设计

    开发遵循原则之一: DRY原则:Don't Repeat Yourself(不要重复你自己的代码) 原因:重复意味着维护成本的增大 public static void main(String[] a ...

  9. 公共表达式消除(UVa 12219)

    紫书354页的题,将表达式树进行公共表达式消除,化为等价的图.因为需要判断某一个是否出现过,所以需要快速比较,采用哈希表的形式,将a~b与1~27一一对应,不采用0,因为0与0000是相同的,对于每一 ...

  10. HTTP 响应实体主体:XML 及 XML parser

    本文内容 HTTP 响应实体主体:XML XML parser 总结 各编程语言实现的 XML parser   HTTP 响应实体主体:XML 实体主体(entity-body)通常是HTTP响应里 ...