将阻塞转成非阻塞
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import socket sk = socket.socket() sk.bind(('127.0.0.1',9090)) sk.setblocking(False) sk.listen() conn_l = [] del_l = [] while True: rf try: conn,addr = sk.accept() conn_l.append(conn) except BlockingIOError as e: for conn in conn_l: try: ret = conn.recv(1024) if ret: print(ret) conn.send(b'hello') else: conn.close() del_l.append(conn) except (BlockingIOError,OSError) :pass for conn in del_l: conn_l.remove(conn) del_l.clear()
TCP协议来说,如果对方关闭了连接
# 另一方有可能继续 接收 空消息 或者 报错
# 另一方有可能继续 接收 空消息 或者 报错
# 背代码
# 将具体的情况套到代码中 将逻辑理顺
# 理解之前IO多路复用的那张图
# 将具体的情况套到代码中 将逻辑理顺
# 理解之前IO多路复用的那张图
# 什么叫IO多路复用
# io多路复用是操作系统提供的一种 监听 网络IO操作的机制
# 监听三个列表
# 当某一个列表有对应的事件发生的时候
# 操作系统通知应用程序
# 操作系统根据返回的内容做具体的操作
# 对于只有一个对象需要监听的情况 IO多路复用并无法发挥作用
# 对于并发接收网络请求的应用场景 IO多路复用可以帮助你在节省CPU利用率和操作系统调用的基础上完成并发需求
# io多路复用是操作系统提供的一种 监听 网络IO操作的机制
# 监听三个列表
# 当某一个列表有对应的事件发生的时候
# 操作系统通知应用程序
# 操作系统根据返回的内容做具体的操作
# 对于只有一个对象需要监听的情况 IO多路复用并无法发挥作用
# 对于并发接收网络请求的应用场景 IO多路复用可以帮助你在节省CPU利用率和操作系统调用的基础上完成并发需求
# IO多路复用
# select 是windows上的机制 轮询的方式来监听每一个对象是否有对应的事件发生的,数据越多延迟越大
# 能够处理的对象数是有限的
# poll linux 和select的机制基本一致,对底层存储被监听对象的数据结构做了优化
# 能够处理的对象个数增加了
# epoll linux 采用了回调函数的方式来通知应用被监听的对象有事件发生了
# select 是windows上的机制 轮询的方式来监听每一个对象是否有对应的事件发生的,数据越多延迟越大
# 能够处理的对象数是有限的
# poll linux 和select的机制基本一致,对底层存储被监听对象的数据结构做了优化
# 能够处理的对象个数增加了
# epoll linux 采用了回调函数的方式来通知应用被监听的对象有事件发生了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# IO多路复用 - 操作系统提供的 # 1.程序不能干预过程 # 2.操作系统之间的差异 import select import socket sk = socket.socket() sk.bind(('127.0.0.1',9090)) sk.listen() sk.setblocking(False) rlst = [sk] while True: rl,wl,xl = select.select(rlst,[],[]) #[sk,conn1,conn2] # 为什么突然把sk返回回来了? sk对象有数据可以被读了 # 为什么返回三个列表? 读事件的列表 写事件的列表 条件的列表 # 为什么是列表? 有可能同时有多个被监听的对象发生读时间 for obj in rl: if obj is sk: # is的意思更精准,判断的是obj就是sk conn,addr = obj.accept() rlst.append(conn) else: try: ret = obj.recv(1024) print(ret) obj.send(b'hello') except ConnectionResetError: obj.close() rlst.remove(obj)