SocketServer 中非常重要的两个基类就是:BaseServer 和 BaseRequestHandler
在SocketServer 中也提供了对TCP以及UDP的高级封装,这次我们主要通过分析关于TCP的处理逻辑来对SocketServer模块进行一个很好的理解和学习

TCPServer

TCPServer 继承了BaseServer,初始化的时候,进行了socket套接字的创建。

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

在这里我们看到了我们非常熟悉的关于socket的创建的内容:
self.socket = socket.socket(self.address_family, self.socket_type)
通过socket模块创建了socket对象,接着调用了server_bind和server_activate

server_bind

源码内容如下:

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()

这里我们看到了非常熟悉的操作socket.bind方法,以及设置了socket的相关属性

server_activate

源码内容如下:

def server_activate(self):
"""Called by constructor to activate the server. May be overridden. """
self.socket.listen(self.request_queue_size)

同样的这里的调用也非常简单就是执行了socket.listen

get_request

在TCPServer类中我们还看到了get_request方法,源码内容如下:

def get_request(self):
"""Get the request and client address from the socket. May be overridden. """
return self.socket.accept()

这个的调用其实我们可以在BaseServer这个基类中看到,我们之前看过关于BaseServer中这个基类的源码
我们可以从我们调用BaseServer基类中的serve_forever方法查看,这里是调用了_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)

可以看到这里最后是调用了process_request来处理请求,继续查看源码:

def process_request(self, request, client_address):
"""Call finish_request. Overridden by ForkingMixIn and ThreadingMixIn. """
self.finish_request(request, client_address)
self.shutdown_request(request) def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)

从上面的代码我们可以到最后是在finish_request中实例化了RequestHandlerClass
我们 这个时候查看一下BaseRequestHandler这个基类的源码如下:

class BaseRequestHandler:

    """Base class for request handler classes.

    This class is instantiated for each request to be handled.  The
constructor sets the instance variables request, client_address
and server, and then calls the handle() method. To implement a
specific service, all you need to do is to derive a class which
defines a handle() method. The handle() method can find the request as self.request, the
client address as self.client_address, and the server (in case it
needs access to per-server information) as self.server. Since a
separate instance is created for each request, the handle() method
can define other arbitrary instance variables. """ def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish() def setup(self):
pass def handle(self):
pass def finish(self):
pass

在初始化函数里我们看到了调用setup()方法,这setup在StreamRequestHandler会被重写

StreamRequestHandler

TCPServer实现了使用tcp套接字的网络服务,Handler方面则是对应的StreamRequestHandler。它继承了BaseRequestHandler。基类的setup方法和finish方法被它重写,用于通过连接实现缓存文件的读写操作。

setup方法

源码内容如下:

def setup(self):
self.connection = self.request
if self.timeout is not None:
self.connection.settimeout(self.timeout)
if self.disable_nagle_algorithm:
self.connection.setsockopt(socket.IPPROTO_TCP,
socket.TCP_NODELAY, True)
self.rfile = self.connection.makefile('rb', self.rbufsize)
self.wfile = self.connection.makefile('wb', self.wbufsize)

这里主要设置了对应连接的属性,其中创建了两个对象非常重要:
一个可读(rfile)和一个可写(wfile)的“文件”对象
但是实际并不是创建了文件,而是封装了读取数据和发送数据的操作,抽象成了对文件的操作
可以理解:
self.rfile 就是读取客户端数据的对象,它有一些方法可以读取数据。self.wfile则是用来发送数据给客户端的对象。

整理流程(TCP)

实现TCP服务需要使用TCPServer和StreamRequestHandler共同协作

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

  1. Dubbo源码学习(二)

    @Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...

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

    在进行gevent源码学习一分析之后,我还对两个比较核心的问题抱有疑问: 1. gevent.Greenlet.join()以及他的list版本joinall()的原理和使用. 2. 关于在使用mon ...

  3. Vue源码学习二 ———— Vue原型对象包装

    Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...

  4. 以太坊 layer2: optimism 源码学习(二) 提现原理

    作者:林冠宏 / 指尖下的幽灵.转载者,请: 务必标明出处. 掘金:https://juejin.im/user/1785262612681997 博客:http://www.cnblogs.com/ ...

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

    一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public cl ...

  6. SocketServer源码学习(一)

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

  7. Thrift源码学习二——Server层

    Thrift 提供了如图五种模式:TSimpleServer.TNonblockingServer.THsHaServer.TThreadPoolServer.TThreadSelectorServe ...

  8. SocketServer源码学习补充

    在前两个文章中整理了关于BaseServer部分以及BaseRequestHandler,以及通过对TCP的处理的流程的整理,这次整理的是剩下的关于用于扩展的部分,这里通过对线程扩展进行整理 Thre ...

  9. mybatis源码学习(二)--mybatis+spring源码学习

    这篇笔记主要来就,mybatis是如何利用spring的扩展点来实现和spring的整合 1.mybatis和spring整合之后,我们就不需要使用sqlSession.selectOne()这种方式 ...

随机推荐

  1. pip安装selenium报错:Read timed out

    今天打算把selenium降级重新安装,发现安装时总是失败,报如下错误: raise ReadTimeoutError(self._pool, None, 'Read timed out.') pip ...

  2. 20145237 实验二 “Java面向对象程序设计”

    20145237 实验二 “Java面向对象程序设计” 实验内容 • 理解并掌握面向对象三要素:封装.继承.多态 • 初步掌握UML建模 • 熟悉S.O.L.I.D原则 • 使用TDD设计实现复数类 ...

  3. JSONP 详解

    1.什么是JSONP ? JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实 ...

  4. python使用tesseract-ocr完成验证码识别(模型训练和使用部分)

    一.Tesseract训练 大体流程为:安装jTessBoxEditor -> 获取样本文件 -> Merge样本文件 –> 生成BOX文件 -> 定义字符配置文件 -> ...

  5. Python内置函数(60)——compile

    英文文档: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) Compile the source i ...

  6. 使用Putty实现windows向阿里云的Linux云服务器上传文件

    1.首先获取PSCP工具 PuTTY小巧方便.但若需要向网络中的Linux系统上传文件,则可以使用PuTTY官方提供的PSCP工具来实现上传.PSCP是基于ssh协议实现. 可以点击这里下载 2.启动 ...

  7. Docker学习笔记 - Docker容器与外部网络的连接

    学习目的: ip_forward 包过滤防护墙 iptables 允许端口映射访问 限制ip访问容器 1.ip_forward 控制系统是否会转发流量 检查linux系统转发是否开启命令:sysctl ...

  8. GIT入门笔记(20)- git 开发提交代码过程梳理

    git开发提交流程新项目开发,可以直接往master上提交老项目维护,可以在分支上修改提交,多次add和commit之后,也可以用pull合并主干和本地master,解决冲突后再push 1.检出代码 ...

  9. angular中的路径问题

    我们在写项目时会遇到启动页调到引导页,引导页再调到首页, 那我们在用angular框架写这种东西的时候如果我们不细心的话就会遇到问题, 比如说找不到引导页的图片等等. 那我们怎么解决这个问题呢? 首先 ...

  10. CNN中减少网络的参数的三个思想

    CNN中减少网络的参数的三个思想: 1) 局部连接(Local Connectivity) 2) 权值共享(Shared Weights) 3) 池化(Pooling) 局部连接 局部连接是相对于全连 ...