🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
**原理图** ![](https://box.kancloud.cn/eadb7b169483f83c311e68102b2b8cc3_655x215.png) 1. Create an epoll object——创建1个epoll对象 2. Tell the epoll object to monitor specific events on specific sockets——告诉epoll对象,在指定的socket上监听指定的事件 3. Ask the epoll object which sockets may have had the specified event since the last query——询问epoll对象,从上次查询以来,哪些socket发生了哪些指定的事件 4. Perform some action on those sockets——在这些socket上执行一些操作 5. Tell the epoll object to modify the list of sockets and/or events to monitor——告诉epoll对象,修改socket列表和(或)事件,并监控 6. Repeat steps 3 through 5 until finished——重复步骤3-5,直到完成 7. Destroy the epoll object——销毁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的控制文件描述符(Return the epoll control file descriptor) epoll.modfiy(fineno,event) fineno为文件描述符 event为事件类型 作用是修改文件描述符所对应的事件 epoll.fromfd(fileno) 从1个指定的文件描述符创建1个epoll对象 epoll.close() 关闭epoll对象的控制文件描述符 ~~~ 注:EPOLLIN(可读),EPOLLOUT(可写) * EPOLLET: 边缘触发模式(只通知一次) * EPOLLLT:水平触发模式(通知后没有做处理的话还会继续通知) ~~~ import socket import select tcp_server_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_server_tcp.bind(('0.0.0.0', 9292)) tcp_server_tcp.listen(128) # 设置套接字为非阻塞方式 tcp_server_tcp.setblocking(False) # 创建一个epoll对象 epl = select.epoll() # 将监听套接字对应的fd注册到epoll中 epl.register(tcp_server_tcp.fileno(), select.EPOLLIN) # fd为key,socket为value fd_event_dict = dict() while True: # 默认阻塞,直到os监测到数据到来,通过事件通知的方式,此时才会解开阻塞 # epl.poll(10) 里面可以写超时时间 fd_event_list = epl.poll() # 结果是这样,[(fd, event), (套接字对应的文件描述符,这个文件描述符到底是什么事件,例如,可以调用recv接收等)] if not fd_event_list: print("epoll超时无活动连接,重新轮询......") continue print("有", len(fd_event_list), "个新事件,开始处理......") for fd, event in fd_event_list: # 如果活动socket为当前服务器socket,表示有新连接 if fd == tcp_server_tcp.fileno(): # 等待新客户端的链接 new_socket, client_addr = tcp_server_tcp.accept() # 注册新连接fd到待读事件集合 epl.register(new_socket.fileno(), select.EPOLLIN) # 把新连接的文件句柄以及对象保存到字典 fd_event_dict[new_socket.fileno()] = new_socket elif event == select.EPOLLIN: # 判断已经链接的客户端是否有数据发送过来 recv__data = fd_event_dict[fd].recv(1024).decode('utf-8', 'ignore') if recv__data: print('收到的数据是: ', recv__data) # 发送数据回去 fd_event_dict[fd].send(recv__data.encode('utf-8')) else: fd_event_dict[fd].close() epl.unregister(fd) del fd_event_dict [fd] ~~~