SocketServer源码学习(一)
SocketServer其实是对socket更高级的封装正如官网上说的:
The socketserver module simplifies the task of writing network servers.
我们可以先打开以下SocketServer的源码,看一下源码中整体的框架
从上图我们可以看出SocketServer主要被抽象为两个主要的类:
BaseServer类,用于处理连接相关的网络操作
BaseRequestHandler类,用于实际处理数据相关的操作
SocketServer还提供了两个MixIn类:ThreadingMinxIn和ForkingMixinl
用于扩展server,实现多进程和多线程
下面从会从这几个主要的类开始做一个整体的分析,了解SocketServer的处理流程
BaseServer
先列一下这里所包含的方法:
server_activate
serve_forever
shutdown
service_actions
handle_request
handlerequest_noblock
handle_timeout
verify_request
process_request
server_close
finish_request
shutdown_request
close_request
handle_error
先看一下BaseServer的初始化函数,其实并没有过多的参数,主要就是实现了创建server对象,并初始化server地址和处理请求的类:RequestHandlerClass
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
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()
当创建server对象之后,我们会使用server对象开启一个无限循环,即调用serve_forever,
下面是它的源码,接受一个参数poll_interval,用于表示select轮询的时间,然后进入一个死循环,用select方法进行网络IO的监听,这里通过调用selector.register(self, selectors.EVENT_READ)进行了注册,当ready有返回是,表示有IO连接或者数据,这个时候会调用_handle_request_noblock
接着看一下_handle_request_noblock源码
handlerequest_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)
handlerequest_noblock方法即开始处理一个请求,并且是非阻塞。该方法通过get_request方法获取连接,具体的实现在其子类。一旦得到了连接,调用verify_request方法验证请求。验证通过,即调用process_request处理请求。如果中途出现错误,则调用handle_error处理错误,以及shutdown_request结束连接。
而verify_request中默认直接返回True,所以当验证通过后讲调用process_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)
就像源码中描述的那样:Overridden by ForkingMixIn and ThreadingMixIn.
process_request方法是mixin的入口,MixIn子类通过重写该方法,进行多线程或多进程的配置。调用finish_request完成请求的处理,同时调用shutdown_request结束请求。继续查看finish_request
finish_request
源码内容如下:
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)
关于请求的部分到这里就已经处理完毕,接下来是要对数据的处理,finish_request方法将会处理完毕请求。创建requestHandler对象,并通过requestHandler做具体的处理。
BaseRequestHandler
就像我们前面说的:
BaseServer类,用于处理连接相关的网络操作
BaseRequestHandler类,用于实际处理数据相关的操作
还是从初始化函数里看源码:
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()
该类会处理每一个请求。初始化对象的时候,设置请求request对象。然后调用setup方法,子类会重写该方法,用于处理socket连接。接下来的将是handler和finish方法。所有对请求的处理,都可以重写handler方法。
SocketServer的一个服务端的简单例子
直接上代码了:
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
try:
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address))
print(self.data)
self.request.sendall(self.data.upper())
except ConnectionResetError as e:
print(e)
break if __name__ == '__main__':
host,port = "127.0.0.1",9999
server = socketserver.TCPServer((host,port),MyTCPHandler)
server.serve_forever()
通过对源码的分析我们已经知道了对数据的处理部分都是在BaseRequestHandler这个类中,而我们的主要处理逻辑也就是在这部分,所以我继承了这个类,重写了handle方法
SocketServer源码学习(一)的更多相关文章
- SocketServer源码学习(二)
SocketServer 中非常重要的两个基类就是:BaseServer 和 BaseRequestHandler在SocketServer 中也提供了对TCP以及UDP的高级封装,这次我们主要通过分 ...
- SocketServer源码学习补充
在前两个文章中整理了关于BaseServer部分以及BaseRequestHandler,以及通过对TCP的处理的流程的整理,这次整理的是剩下的关于用于扩展的部分,这里通过对线程扩展进行整理 Thre ...
- 文件上传下载、socketserver(并发)、解读socketserver源码
1.文件上传/下载 学习了socket套接字,我们现在可以写一个文件上传/下载的程序,如下示例: 分析上边代码,我们发现,client发送上传文件相关信息的字典序列化之后,server又给client ...
- python day 15: IO多路复用,socketserver源码培析,
目录 python day 15 1. IO多路复用 2. socketserver源码分析 python day 15 2019/10/20 学习资料来自老男孩教育 1. IO多路复用 ''' I/ ...
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- jQuery源码学习感想
还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码, ...
- MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)
前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...
- MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)
前言:上篇介绍了下自己的MVC框架前两个版本,经过两天的整理,版本三基本已经完成,今天还是发出来供大家参考和学习.虽然微软的Routing功能已经非常强大,完全没有必要再“重复造轮子”了,但博主还是觉 ...
- MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)
前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...
随机推荐
- shell之九九乘法表
echo -n 不换行输出 $echo -n "123" $echo "456" 最终输出 123456 而不是 123 456 echo - ...
- RESTFul API设计指南及使用说明
RESTFul API设计指南及使用说明 一. 协议 API与用户的通信协议,使用HTTP协议. 二. 域名 应尽量将API部署在专用域名之下(http://api.example.com) 也可以将 ...
- HIVE的常用操作(HQL)语句
HIVE基本操作命令 创建数据库 >create database db_name; >create database if not exists db_name;//创建一个不存在的数据 ...
- MySQL之数据库和表的基本操作(建立表、删除表、向表中添加字段)
介绍关于数据库和表的一些基本操作 添加字段.给字段添加注释 ); ) COMMENT '统一社会信用代码录入单位'; ,) 更改字段类型 ,) COMMENT '一头签收,@0或空不用,1必须'; 有 ...
- Mysql-5.7.21安装配置
搞开发多年,其实MySql前前后后安装配置了无数次,但是每次都需要到网上搜教程,折腾半天才搞定,这次索性把整个过程全部记录下来,以便以后查阅. 下载 到MySql官网,导航找到DOWNLOADS> ...
- 微信开发之SVN提交代码与FTP同步到apache的根目录
SVN是协同开发的,版本控制器,就是几个人同时开发,可以提交代码到SVN服务器,这样就可以协同开发,一般是早上上班首先更新下代码,然后自己修改代码 工作一天之后,修改代码之后,下班之前,更新代码,然后 ...
- thinkphp中ajax技术
thinkphp可以直接返回json数据,json数据事可以跟前端的js通用的
- linux——网络基础
装完linux系统要对网络(ip地址,子网掩码,网关,DNS)进行配置,才能连接网络 一,开启网卡eth0 CentOS显示没有网卡(eth0) 2.设置静态IP vim /etc/sysconfig ...
- cannot import name 'ChineseAnalyzer'
在python3.6下安装jieba3k的时候报错: from jieba.analyse import ChineseAnalyzer ImportError: cannot import name ...
- 【笔记】HybridApp中使用Promise化的JS-Bridge
背景: HybridApp,前端采用JS-bridge的方式调用Native的接口,如获取设备信息.拍照.人脸识别等 前端封装了调用库,每次调用Native接口,需要进行两步操作(1.在window下 ...