使用select异步IO实现socketserver服务器 源码剖析
#_*_coding:utf-8_*_
#这是一个echo server,客户端消息,服务端回复相同的消息
import select, socket, sys, queue # Create a TCP/IP socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #对socket进行实例化,拿到server句柄
server.setblocking(False) #设置server为不阻塞 # Bind the socket to the port
server_address = ('localhost', 10000) #将主机名,端口号赋值给server_address
print(sys.stderr, 'starting up on %s port %s' % server_address) #如有错误信息,输出,并打印strting up...
server.bind(server_address) #绑定服务器ip端口号给socket实例化后的句柄 # Listen for incoming connections
server.listen(5) #允许最大监听链接5 # Sockets from which we expect to read
inputs = [ server ] #设置客户端和服务端的socket句柄列表,后续都会append到其中 # Sockets to which we expect to write
outputs = [ ] #设置echo给客户端的socket句柄,后续会append到其中 message_queues = {} #设置消息队列字典,后续存放
while inputs: #维护所有服务端和客户端过来的连接 # Wait for at least one of the sockets to be ready for processing
print( '\nwaiting for the next event')
readable, writable, exceptional = select.select(inputs, outputs, inputs) #执行select.select方法,将输入的句柄、输出的句柄和错误信息,分别赋值给readable、writeable、exceptional
# Handle inputs
for s in readable: #遍历服务端和客户端请求过来的socket句柄 if s is server: #如果是客户端连接的句柄
# A "readable" server socket is ready to accept a connection
connection, client_address = s.accept() #接收连接请求
print('new connection from', client_address) #打印新请求连接信息
connection.setblocking(False) #设置为连接非阻塞,否则即使将会hang住
inputs.append(connection) #将客户端连接的句柄append到inputs列表,下一次select的时候能够检测这个连接 # Give the connection a queue for data we want to send
message_queues[connection] = queue.Queue() #连接进来后,把发的消息放到这个队列;以连接的句柄作为key,来以字典形式存放队列信息,保证每个连接的句柄发送的数据都是隔离的
else: #如果是服务端连接的句柄
data = s.recv(1024) #接收客户端发来的数据
if data: #如果客户端发过来的数据不为空
# A readable client socket has data
print(sys.stderr, 'received "%s" from %s' % (data, s.getpeername()) ) #如果有错误,打印错误信息
message_queues[s].put(data) #放到以客户端socket的句柄为key的字典里,数据作为value存放
# Add output channel for response
if s not in outputs: 如果当前客户端的连接句柄没有在outputs这个待发送的列表中
outputs.append(s) #先不给客户端发送其发来的数据,因为如果客户端没有空闲,就会造成阻塞。先把要发送的数据append到outputs自己维护的这个列表,下次select的时候,这个列表就不为空了,那个时候再给客户端发送数据
else: #如果客户端发过来的数据是空
# Interpret empty result as closed connection
print('closing', client_address, 'after reading no data') #打印关闭信息
# Stop listening for input on the connection
if s in outputs: #如果当前客户端的句柄,在要回复数据的列表中
outputs.remove(s) #既然客户端都断开了,我就不用再给它返回数据了,所以这时候如果这个客户端的连接对象还在outputs列表中,就把它删掉
inputs.remove(s) #inputs中也删除掉
s.close() #把这个连接关闭掉 # Remove message queue
del message_queues[s] #删掉客户端这个socket发过来的数据
# Handle outputs
for s in writable: #这是要给客户端回复数据的列表,这列表是自己维护的
try:
next_msg = message_queues[s].get_nowait() #取出当前客户端的socket句柄对应的消息
except queue.Empty: #如果这个客户端的socket句柄对应的消息是空的话
# No messages waiting so stop checking for writability.
print('output queue for', s.getpeername(), 'is empty') #打印空队列消息
outputs.remove(s) #移除这个客户端的socket句柄
else: #如果没有报错的话
print( 'sending "%s" to %s' % (next_msg, s.getpeername())) #打印发送数据
s.send(next_msg) #服务器真正给客户端发送之前客户端发过来的数据
# Handle "exceptional conditions"
for s in exceptional: #在客户端断开的情况下,会赋值给exceptional
print('handling exceptional condition for', s.getpeername() ) #打印错误信息
# Stop listening for input on the connection
inputs.remove(s) #删除客户端socket对应的句柄
if s in outputs: #如果在要发的消息列表中存在客户端的socket句柄
outputs.remove(s) #删除客户端的socket句柄
s.close() #服务器关闭这个客户端先断开的连接 # Remove message queue
del message_queues[s] #删除掉客户端socket句柄对应的消息
使用select异步IO实现socketserver服务器 源码剖析的更多相关文章
- select用法&原理详解(源码剖析)(转)
今天遇到了在select()前后fd_set的变化问题,查了好久终于找到一个有用的帖子了,很赞,很详细!!原文链接如下: select用法&原理详解(源码剖析) 我的问题是: 如下图示:在se ...
- socket_server源码剖析、python作用域、IO多路复用
本节内容: 课前准备知识: 函数嵌套函数的使用方法: 我们在使用函数嵌套函数的时候,是学习装饰器的时候,出现过,由一个函数返回值是一个函数体情况. 我们在使用函数嵌套函数的时候,最好也这么写. def ...
- IO多路复用及ThreadingTCPServer源码阅读
IO多路复用 socket模块是阻塞的,通过socket建立的服务端可以接收多个请求,但只能同时处理一个请求,其他请求都被阻塞.可以通过IO多路复用解决这个问题,socketserver内部使用的就是 ...
- 自己实现多线程的socket,socketserver源码剖析
1,IO多路复用 三种多路复用的机制:select.poll.epoll 用的多的两个:select和epoll 简单的说就是:1,select和poll所有平台都支持,epoll只有linux支持2 ...
- socketserver 源码剖析:
socketserver 源码剖析[有图有真相]: (一).Socketserver 内部流程调用图: 详解: 1.self.RequestHandlerClass() = MyCla ...
- rsyn实现服务器源码同步
近期技术总监提出,要建立预生产环境,代码实现灰度发布.需要多台服务器源码保持一致. 实施步骤 1.安装rsyn服务端并添加环境变量. 2.安装客户端并配置环境变量. 3.更改配置文件并开放防火墙端口. ...
- 图解 Java IO : 二、FilenameFilter源码
Writer :BYSocket(泥沙砖瓦浆木匠) 微 博:BYSocket 豆 瓣:BYSocket FaceBook:BYSocket Twitter ...
- Socketserver的源码分析
Socketserver的源码分析
- tiny web服务器源码分析
tiny web服务器源码分析 正如csapp书中所记,在短短250行代码中,它结合了许多我们已经学习到的思想,如进程控制,unix I/O,套接字接口和HTTP.虽然它缺乏一个实际服务器所具备的功能 ...
随机推荐
- svn clearup svn cleanup failed–previous operation has not finished; run cleanup if it was int错误的解决办法
今天svn提交,出现异常:svn cleanup failed–previous operation has not finished; run cleanup if it was interrupt ...
- 不同种类的PI膜及其特性
一.PI膜种类及其特性 1.聚酰亚胺材料分类 聚酰亚胺材料可分为热塑性聚酰亚胺和热固性聚酰亚胺(包括双马来酰亚胺型和单体反应聚合型聚酰亚胺及各自改性产品)两大类 其中,热塑性聚酰亚胺材料一般采用两步法 ...
- 软件测试第2周个人作业:WordCount编码测试
一.Github地址 https://github.com/zhouyubei/WordCount 二.PSP表格 PSP2.1 PSP阶段 预估耗时 (分钟) 实际耗时 (分钟) Planning ...
- 基于vue-cli项目打包慢的定位优化过程
入职一周后,上一个前端就离职了(超级坑爹的),留下了一个比较棘手的问题,就是基于vue-cli的项目打包超级慢,我接手项目的时候,打包需要45min(上个离职者也不知道原因),经过3个月之后,随着项目 ...
- Java中对JSONArray中的对象进行排序
String jsonArrStr = "[ { \"ID\": \"135\", \"Name\": \"Fargo ...
- Java笔记1: 输入输出与变量常量
输入方法 nextLine 以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符. 可以获得空白的一串字符. import java.util.Scanner; pu ...
- python中全局global和局部nonlocal命名空间
python中全局global和局部nonlocal命名空间 局部名称空间对全局名称空间的变量可以引用,但是无法改变. count = 1 def func1(): count = 2 print(c ...
- TIPTOP之分割split函数方法、getIndexOf、subString、replace、临时表创建;
范例(cnmq001): 原:每次查询都把数据全部查询到临时表后再筛选: 现:查询到临时表的时候,增加可行的筛选条件,再二次筛选临时表的数据,进行优化: 1)临时表创建: PRIVATE FUNCTI ...
- Hinton等人新研究:如何更好地测量神经网络表示相似性
Hinton等人新研究:如何更好地测量神经网络表示相似性 2019年05月22日 08:39:15 喜欢打酱油的老鸟 阅读数 177更多 分类专栏: 人工智能 https://www.toutia ...
- SpringBoot 初入门
SpringBoot 初入门 关于介绍什么之类的就不讲了,主要做一下学习记录. 1. 启动方式 IDEA 启动 命令行启动: mvn spring-boot:run 部署到服务器启动: 先进行打包, ...