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. Java 多线程并发编程之 Synchronized 关键字

    synchronized 关键字解析 同步锁依赖于对象,每个对象都有一个同步锁. 现有一成员变量 Test,当线程 A 调用 Test 的 synchronized 方法,线程 A 获得 Test 的 ...

  2. js中的类型转换

    先介绍一下 typeof 的使用方法: typeof(mix)   或者  typeof  mix 其中 mix 可以是任何数据类型 typeof 的返回值有六种:number.string.bool ...

  3. 利用1.1.1.1进行DNS网络加速,仅需2分钟让网络更快

    NEWS 近日,Cloudflare 和 APNIC联合推出了1.1.1.1DNS网络加速. Cloudflare 运行全球规模最大.速度最快的网络之一.APNIC 是一个非营利组织,管理着亚太和大洋 ...

  4. backpropagation

    github: https://github.com/mattm/simple-neural-network blog: https://mattmazur.com/2015/03/17/a-step ...

  5. 2017-2018-1 1623 bug终结者 冲刺006

    bug终结者 冲刺006 by 20162328 蔡文琛 今日任务:音频素材添加 又是新的一天,小组项目有了很大的起色,已经可以在手机上试玩了. 添加背景音乐能使我们的游戏锦上添花. 音频资源需求 需 ...

  6. 【基础知识】Flex-弹性布局原来如此简单!!

    简言 布局的传统解决方案是基于盒状模型,依赖 display + position + float 方式来实现,灵活性较差.2009年,W3C提出了一种新的方案-Flex,Flex是Flexible ...

  7. java的socket通信

    本文讲解如何用java实现网络通信,是一个非常简单的例子,我比较喜欢能够立马看到结果,所以先上代码再讲解具体细节. 服务端: import java.io.BufferedReader; import ...

  8. 2018年东北农业大学春季校赛-wyh的吃鸡

    BFS: 1. 从起点开始BFS,遇到X点则return: 2. vis[px][py][0]代表经过pxpy这点前还没有找到车: vis[px][py][1]代表经过pxpy这点前已经找到车: 3. ...

  9. 剑指offer-第一个只出现一次的字符

    题目描述 在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置   解题思路 由于char类型一共有256种可能,所以开辟一个数组ha ...

  10. 新特性GTID

    什么是GTID 每提交一个事务,当前的执行过程都会拿到一个唯一的标识符,此标识符不仅对其源mysql 实列是唯一的而在给定的复制环境中的所有mysql 实列也是唯一的,所哟的事务与其GTID 之间都是 ...