[toc]
下面将以socket网络通信为例,分别通过非阻塞IO和多路复用IO来进行代码实现
## 非阻塞IO
### server端代码
主要就是将setblocking设置为False后,通过捕获抛出的异常,以判断是否有新连接,是否有接受到数据,然后不停的while循环来实现
~~~
import socket
server=socket.socket()
server.bind(('127.0.0.1',8800))
server.listen()
server.setblocking(False)
con_list=[]
rm_list=[]
while True:
try:
conn,addr=server.accept()
con_list.append(conn)
except BlockingIOError:
for conn in con_list:
try:
msg=conn.recv(1024)
conn.send(b'my server')
except BlockingIOError:pass
except ConnectionResetError:
rm_list.append(conn)
conn.close()
for conn in rm_list:
con_list.remove(conn)
else:
rm_list.clear() #删除关闭的client
server.close()
~~~
### client端代码
~~~
import socket,os,time
client=socket.socket()
client.connect(('127.0.0.1',8800))
while True:
msg='my client:%s'%os.getpid()
print(msg)
client.send(msg.encode())
time.sleep(1)
print(client.recv(1024))
~~~
## 多路复用IO
多路复用,是使用了一个代理`select`来做监听的动作,避免了前一种方式`while循环`的资源消耗
### server端代码
~~~py
import socket,select
server = socket.socket()
server.bind(('127.0.0.1', 8800))
server.listen(5)
server.setblocking(False) #设置为非阻塞
print('server is start ......')
rlist = [server, ] # 读列表,初始只有server
wlist = [] # 写列表
xlist = [] # 异常列表
while True:
rl, wl, xl = select.select(rlist, wlist, xlist)
# print('rlist:', rlist)
for sk in rl:
if sk == server: # 如果是server则建立连接并添加conn到列表
conn, addr = sk.accept()
rlist.append(conn) #
else: # 如果是conn,则收发数据
try:
conn = sk
msg = conn.recv(1024).decode()
if not msg:#客户端关闭则删除conn(linux)
conn.close()
rlist.remove(sock)
continue
print('接收消息:', msg)
conn.send(msg.upper().encode())
except ConnectionResetError: #客户端关闭则删除conn(windows)
conn.close()
rlist.remove(conn)
~~~
### client端代码
~~~py
import socket
client=socket.socket()
client.connect(('127.0.0.1',8800))
while True:
msg=input('>>:')
if not msg:continue
client.send(msg.encode())
data=client.recv(1024)
print(data.decode( ))
~~~
## 基于selectors的IO多路复用
**selectors模块**
* 此模块允许基于选择模块原语构建高级别和高效的I / O多路复用。
* 鼓励用户使用此模块,除非他们想要精确控制使用的os级别的原语。
注:selectors也是包装了select高级的包装内置函数,它包装了select与epoll,优先使用epoll,windos内只支持select。
### server端代码
~~~py
import selectors
import socket
sock = socket.socket()
sock.bind(('127.0.0.1', 8800))
sock.listen(5)
sock.setblocking(False)
sel = selectors.DefaultSelector() # 生成select实例对象
def read(conn, mask):
try:
data = conn.recv(1024)
if not data:
print('closing', conn)
sel.unregister(conn)
conn.close()
return
conn.send(data.upper() + b'_SB')
except Exception:
print('closing', conn)
sel.unregister(conn) # 取消注册
conn.close() # 关闭连接
def accept(sock, mask):
conn, addr = sock.accept()
print('-------', conn)
# 注册conn,回调 read函数
sel.register(conn, selectors.EVENT_READ, read)
# 注册server事件:
# 参数1:sock 进行监听
# 参数2:selectors.EVENT_READ 执行动作
# 参数3:accept,只要来一个链接就回调这个函数
sel.register(sock, selectors.EVENT_READ, accept)
while True:
print('wating....')
events = sel.select() # 调用select:优先使用epoll
# 默认阻塞,有活动链接就返回活动的链接列表
for key, mask in events:
# callback相当于调accept函数
callback = key.data
# 获取函数内存地址,加入参数
# key.fileobj = 文件句柄
callback(key.fileobj, mask)
~~~
### client端代码
~~~py
import socket
client=socket.socket()
client.connect(('127.0.0.1',8800))
while True:
msg=input('>>:')
if not msg:continue
client.send(msg.encode())
data=client.recv(1024)
print(data.decode( ))
~~~
- 基础部分
- 基础知识
- 变量
- 数据类型
- 数字与布尔详解
- 列表详解list
- 字符串详解str
- 元组详解tup
- 字典详解dict
- 集合详解set
- 运算符
- 流程控制与循环
- 字符编码
- 编的小程序
- 三级菜单
- 斐波那契数列
- 汉诺塔
- 文件操作
- 函数相关
- 函数基础知识
- 函数进阶知识
- lambda与map-filter-reduce
- 装饰器知识
- 生成器和迭代器
- 琢磨的小技巧
- 通过operator函数将字符串转换回运算符
- 目录规范
- 异常处理
- 常用模块
- 模块和包相关概念
- 绝对导入&相对导入
- pip使用第三方源
- time&datetime模块
- random随机数模块
- os 系统交互模块
- sys系统模块
- shutil复制&打包模块
- json&pickle&shelve模块
- xml序列化模块
- configparser配置模块
- hashlib哈希模块
- subprocess命令模块
- 日志logging模块基础
- 日志logging模块进阶
- 日志重复输出问题
- re正则表达式模块
- struct字节处理模块
- abc抽象类与多态模块
- requests与urllib网络访问模块
- 参数控制模块1-optparse-过时
- 参数控制模块2-argparse
- pymysql数据库模块
- requests网络请求模块
- 面向对象
- 面向对象相关概念
- 类与对象基础操作
- 继承-派生和组合
- 抽象类与接口
- 多态与鸭子类型
- 封装-隐藏与扩展性
- 绑定方法与非绑定方法
- 反射-字符串映射属性
- 类相关内置方法
- 元类自定义及单例模式
- 面向对象的软件开发
- 网络-并发编程
- 网络编程SOCKET
- socket简介和入门
- socket代码实例
- 粘包及粘包解决办法
- 基于UDP协议的socket
- 文件传输程序实战
- socketserver并发模块
- 多进程multiprocessing模块
- 进程理论知识
- 多进程与守护进程
- 锁-信号量-事件
- 队列与生产消费模型
- 进程池Pool
- 多线程threading模块
- 进程理论和GIL锁
- 死锁与递归锁
- 多线程与守护线程
- 定时器-条件-队列
- 线程池与进程池(新方法)
- 协程与IO模型
- 协程理论知识
- gevent与greenlet模块
- 5种网络IO模型
- 非阻塞与多路复用IO实现
- 带着目标学python
- Pycharm基本使用
- 爬虫
- 案例-爬mzitu美女
- 案例-爬小说
- beautifulsoup解析模块
- etree中的xpath解析模块
- 反爬对抗-普通验证码
- 反爬对抗-session登录
- 反爬对抗-代理池
- 爬虫技巧-线程池
- 爬虫对抗-图片懒加载
- selenium浏览器模拟