非阻塞IO
利用异常处理来处理非阻塞IO产生的异常
import socket
server = socket.socket() # 生成一个socket对象
server.setblocking(False) # 设置非阻塞套接字
server.bind(('127.0.0.1', 5959)) # 绑定IP 端口
server.listen(5) # 监听数量 也就是允许连接客户端数量
# 一直接收 避免阻塞
while True:
try:
conn, addr = server.accept() # 对等套接字为一个元组对象 进行元组拆包
data = conn.recv(1024) # 接收客户端发送的数据
except BlockingIOError:
pass
except Exception as e:
print('未知异常', e)
实现并发
并发:指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行
并行:指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序是在不同的处理机上运行,并任一个时刻点上有多个程序在不同处理机上运行
import socket
server = socket.socket() # 生成一个socket对象
server.setblocking(False) # 非阻塞IO,针对客户端连接
server.bind(('127.0.0.1', 5959))# 绑定IP 端口
server.listen(5)# 监听数量 也就是允许连接客户端数量
all_conn = [] #定义一个空列表,用来存放对等连接套接字
while True:
try:
conn,addr = server.accept() #不停地生成对等连接套接字,用来接收不同客户端
conn.setblocking(False) #非阻塞IO,针对数据的传输
all_conn.append(conn) # 把套接字放进列表
except BlockingIOError:
pass
except Exception as e:
print('未知异常',e)
for conn in all_conn:
try:
recv_data = conn.recv(1024)
if recv_data: # 如果有数据
print(recv_data)
conn.send(recv_data) #把数据发回客户端
else: #如果没有数据
conn.close()
all_conn.remove(conn)
except BlockingIOError:
pass
except Exception as e:
print('未知异常',e)
复用器
IO多路复用:
在之前的非阻塞IO模型中,通过不断的询问来查看是否有数据,这会造成资源的浪费。
将查看的过程由主动的查询,变成交给复用器完成,这样能够更加节省系统资源,并且性能更好
import socket
import selectors # IO多路复用器选择模块
epoll_select = selectors.EpollSelector() # 实例化一个复用器对象epoll,linux独有
# de_select = selectors.DefaultSelector() # 默认选择器
server = socket.socket() # 生成一个socket对象
server.bind(('127.0.0.1', 5959)) # 绑定IP 端口
server.listen(5) # 监听数量 也就是允许连接客户端数量
def f_recv(conn):
recv_data = conn.recv(1024) # 通过对等连接套接字接收数据
if recv_data:
print(recv_data)
conn.send(recv_data)
else:
conn.close()
def f_accept(server):
conn, addr = server.accept() # 创建对等套接字
epoll_select.register(conn, selectors.EVENT_READ, f_recv)
# 注册方法, selectors.EVENT_READ有事件发生是就会执行回调函数
epoll_select.register(server, selectors.EVENT_READ, f_accept)
while True:
events = epoll_select.select() # 查询复用器,只要有数据,就查出来
# print(events)
for key, mask in events:
# print(key)
func = key.data # 函数体
conn = key.fileobj
func(conn)
非阻塞套接字与IO多路复用:
非阻塞套接字需要自身遍历每个对等连接套接字,并且每次都是进行的IO操作
复用器不需要进行大量的IO操作,复用器会告诉你哪个对等连接套接字有数据过来,然后再去处理即可
epoll:
epoll是一个惰性事件回调,即回调过程是用户自己去调用的,操作系统只起到通知的作用。
epoll是Linux上最好的IO多路复用器,但是也只有在Linux上有,在其他的地方没有。