Python 源码学习二(SocketServer)

SocketServer这个模块中定义的类比较多,但是设计比较清晰,我们以TCPServer为主线分析,先脉络再细节。

总体脉络

将相关类分为两组,如图:

服务器相关(上)

BaseServer是server基础类,定义server的基本处理运行与request处理机制,TCPServer直接继承它。

Request处理类RequestHandler(下)

BaseRequestHandler是request处理的基础类,TCPServer的request处理类StreamRequestHandler直接继承它。

TCPServer设计细节

从类的设计上说,这里可以说时mixin的最佳实践了,什么是mixin?如何使用mixin?

A mixin is a special kind of multiple inheritance. There are two main situations where mixins are used:

1 You want to provide a lot of optional features for a class.

2 You want to use oRequestHandlerClassne particular feature in a lot of different classes.

在这些类的设计中始终围绕如何处理socket请求。通常,处理方式三种:

synchronous (one request is handled at a time)

forking (each request is handled by a new process)

threading (each request is handled by a new thread)

其中,BaseServer作为基础类,实现服务器的监听以及同步处理方法。初始化参数有两个:server_address和RequestHandlerClassserver_forever方法中使用select方式轮询,是否有客户端连接到服务器。

def serve_forever(self, poll_interval=0.5):
    self.__is_shut_down.clear()
    try:
      while not self.__shutdown_request:
        r, w, e = _eintr_retry(select.select, [self], [], [],poll_interval)
      if self in r:
        self._handle_request_noblock()
    finally:
      self.__shutdown_request = False
      self.__is_shut_down.set()

如果有客户端连接,则使用同步的方式进行处理,最终调用一个RequestHandlerClass类进行处理。

def _handle_request_noblock(self):
     try:
      request, client_address = self.get_request()
     except socket.error:
      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)

  def process_request(self, request, client_address):
    self.finish_request(request, client_address)
    self.shutdown_request(request)

   def finish_request(self, request, client_address):
    self.RequestHandlerClass(request, client_address, self)

其中,TCPServer继承自BaseServer,加入了TCP的一些配置,但是运行机制时完全继承的。所以,此时的TCPServer就是第一种情情况。而多进程和多线程方式则通过mixin设计而成。以多线程的ThreadingTCPServer为例:

class ThreadingMixIn:
  daemon_threads = False
  def process_request_thread(self, request, client_address):
    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):
    t = threading.Thread(target = self.process_request_thread,
               args = (request, client_address))
    t.daemon = self.daemon_threads
    t.start()

在ThreadingMixIn类中,覆写process_request方法,对于每个request都创建一个线程进行处理。此时,多线程的情况只要这样:

class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

注意,mixin类要放在前面,因为它覆写了TCPServer类的process_request方法。

在SocketServer完美体现了mixin两个设计原则:

ThreadingMixIn这个mixin类作为一个多线程的特性附加在了TCPServer上,同时这个特性又不仅仅是提供给TCPServer使用,还给UDPServer使用。

时间: 2024-11-11 16:27:54

Python 源码学习二(SocketServer)的相关文章

python源码学习(一)——python的总体架构

python源码学习(一)——python的总体架构 学习环境: 系统:ubuntu 12.04 STLpython版本:2.7既然要学习python的源码,首先我们要在电脑上安装python并且下载python的源码,ubuntu 12.04 STL自带的python版本为2.7.3,这就可以了,接下来下载源码,下载python2.7.7的源代码,下载结束后解压文件,我们会看到如下文件结构:,接下来介绍一下,demo文件夹里放的是一些例子:Doc文件夹里放的是文档,Grammer是语法分析器,

Dubbo源码学习(二)

@Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Adaptive { String[] value() default {}; } @Adapt

python 协程库gevent学习--gevent源码学习(二)

在进行gevent源码学习一分析之后,我还对两个比较核心的问题抱有疑问: 1. gevent.Greenlet.join()以及他的list版本joinall()的原理和使用. 2. 关于在使用monkey_patchall()之后隐式切换的问题. 下面我将继续通过分析源码及其行为来加以理解和掌握. 1. 关于gevent.Greenlet.join()(以下简称join)先来看一个例子: import gevent def xixihaha(msg): print(msg) gevent.sl

Python源码学习(一)

考虑到性能的要求,我在工作中用的最多的是c/c++,然而,工作中又经常会有一些验证性的工作,这些工作对性能的要求并不高,反而对完成的效率要求更高,对于这样的工作,用一种开发效率高的语言是合理的想法,鉴于python的流行以及为大家所称道的开发效率和灵活性,我便开始渐渐多的接触起python来.可是,问题又来了,用python验证完了之后,需要优化性能,甚至移植到c/c++里面来,这时候,愈发觉得有必要深入学习python,了解其内部原理.经过一番搜索,找到了这本<Python源码剖析>,开始了

[spring源码学习]二、IOC源码——配置文件读取

一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void sayHello

Nmap 源码学习二 整体架构

目录功能: docs :相关文档 libdnet-stripped :开源网络接口库 liblinear:开源大型线性分类库 liblua:开源Lua脚本语言库 libnetutil:基本的网络函数 libpcap:开源抓包库 libpcre:开源正则表达式库 macosx:xcode项目文件 mswin32:vs项目文件 nbase:Nmap封装的基础使用函数库 ncat:netcat网络工具,由Nmap实现 ndiff:比较Nmap扫描结果的实用命令 nmap-update:负责Nmap更新

Bottle 框架源码学习 二

上一篇简单分析了route的基本用法 本篇分析一下run函数的运行原理 def run(app=None, server='wsgiref', host='127.0.0.1', port=8080,         interval=1, reloader=False, quiet=False, plugins=None,         debug=None, **kargs):          if NORUN: return     if reloader and not os.env

jQuery源码学习(二)

回调对象Callbacks 回调对象Callbacks就是用来管理回调函数队列的. 参数说明 它提供几个便捷的处理参数 - once: 确保这个回调列表只执行一次 - memory: 保持以前的值,将添加到这个列表的后面的最新的值立即执行调用任何回调 - unique: 确保一次只能添加一个回调(所以在列表中没有重复的回调). - stopOnFalse: 当一个回调返回false 时中断调用 once和stopOnFalse作用于fire memory和unique作用于add once在源码

Thrift源码学习二——Server层

Thrift 提供了如图五种模式:TSimpleServer.TNonblockingServer.THsHaServer.TThreadPoolServer.TThreadSelectorServer ?? TSimpleServer.TThreadPoolServer 属于阻塞模型 TNonblockingServer.THsHaServer.TThreadedSelectorServer 属于非阻塞模型 TServer TServer 为抽象类 public static class Ar