epoll
select存在的问题
- select,需要遍历socket列表,频繁的对等待队列进行添加移除操作
- 数据到达后还需要遍历所有的socket才能获知哪些socket有数据
两个操作消耗的时间随着要监控的socket的数量增加而大大增加,所以最大只能监视1024个socket。
于是就推出了epoll,epoll对问题一方案是把等待队列的维护与阻塞进程这两个操作分开了
对问题2是自己维护了一个等待队列,避免了遍历所有的socket。需要注意:epoll仅能在linux中使用
epoll相关函数
import select # 导入select模块 epoll = select.epoll() # 创建一个epoll对象 epoll.register(文件句柄,事件类型) # 注册要监视的文件句柄和事件 # 事件类型: select.EPOLLIN # 可读事件 select.EPOLLOUT # 可写事件 select.EPOLLERR # 错误事件 select.EPOLLHUP # 客户端断开事件 epoll.unregister(文件句柄) # 销毁文件句柄 epoll.poll(timeout) # 当文件句柄发生变化,则会以列表的形式主动报告给用户进程,timeout为超时时间,默认为-1,即一直等待直到文件句柄发生变化,如果指定为1,那么epoll每1秒汇报一次当前文件句柄的变化情况,如果无变化则返回空 epoll.fileno() # 返回epoll的控制文件描述符 epoll.modify(fineno, event) # 修改文件描述符所对应的事件 epoll.fromfd(filena) # 从1个指定的文件描述符创建1个epoll对象 epoll.close() # 关闭epoll对象的控制文件描述符
案例
import select from socket import * server = socket() server.bind(('127.0.0.1', 8000)) server.listen(5) # 创建一个epoll对象 epoll = select.epoll() # 注册读就绪事件(有数据可以读取了) # s.fileno()用于获取文件描述符 epoll.register(server.fileno(), select.EPOLLIN) # 存储文件描述符与socket的对应关系 fd_socket = {server.fileno(): server} msgs = [] while True: # 会阻塞,直到你关注的事件发生 for fd, event in epoll.poll(): sock = fd_socket[fd] print(fd, event) # 返回的是文件描述符,需要获取对用socket if sock == server: client, addr = server.accept() # 注册客户端写就绪 epoll.register(client.fileno(), select.EPOLLIN) # 添加对应关系 fd_socket[client.fileno()] = client # 读就绪 elif event == select.EPOLLIN: data = sock.recv(1024) if not data: # 注销事件 epoll.unregister(fd) # 关闭socket socket.close() # 删除socket对应关系 del fd_socket[fd] print("somebody ....") continue print(data.decode('utf8')) # 读完数据,需要把数据发回去。所以接下来更改为写就绪事件 epoll.modify(fd, select.EPOLLOUT) # 记录数据 msgs.append((sock, data.upper())) elif event == select.EPOLLOUT: for item in msgs[:]: if item[0] == sock: sock.send(item[1]) msgs.remove(item) # 切换关注事件为写就绪 epoll.modify(fd, select.EPOLLIN)
来源:https://www.cnblogs.com/863652104kai/p/11166025.html