poll 和 epoll
poll只是简单对select进行了优化,但是还不够完美 ,epoll才是最后的解决方案
注意:epoll仅能在linux中使用
案例:
import socket
import select
s = socket.socket()
s.bind(("127.0.0.1",1689))
s.listen()
# 创建一个epoll对象
epoll = select.epoll()
# 注册读就绪事件 (有数据可以读取了)
# s.fileno()用于获取文件描述符
epoll.register(s.fileno(),select.EPOLLIN)
# 存储文件描述符与socket的对应关系
fd_sockets = {s.fileno():s}
while True:
# 该函数是阻塞会直到你关注的事件发生
# 返回值为文件描述符与发生的事件类型 是一个列表 列表中是元组 第一个是描述符 第二个是事件
for fd,event in epoll.poll():
print("有socket 搞事情了!")
sock = fd_sockets[fd] # 取出对应的socket对象
# 判断socket是服务器还是客户端
if sock == s:
# 执行对应的接收或发送
client,addr = sock.accept()
# 注册客户端的事件
epoll.register(client.fileno(),select.EPOLLIN)
# 将对应关系存储到字典中
fd_sockets[client.fileno()] = client
print("来了一个客户端....")
elif event == select.EPOLLIN: #客户端的处理
data = sock.recv(1024)
if not data:
epoll.unregister(fd) # 注销事件
fd_sockets.pop(fd) # 从字典中删除
sock.close() # 关闭socket
continue
print("%s 发来问候:%s" % (sock,data.decode("utf-8")))
#将事件转换为可写
epoll.modify(fd,select.EPOLLOUT)
else:
sock.send("我是服务器 你丫是谁?".encode("utf-8"))
# 将事件转换为可读
epoll.modify(fd, select.EPOLLIN)
epoll 如何解决select的两个问题
1.epoll 把对于等待队列的操作 与阻塞进程分开了
2.epoll 自己维护了一个等待队列 避免了遍历所有socket