epoll 多路复用 I/O工作流程

从业务逻辑上,了解一下 epoll 多路复用 I/O 的工作流程。

有兴趣了解 epoll 源码实现,可以参考: 《[epoll 源码走读] epoll 实现原理


1. epoll

epoll 是一个 Linux 系统的一个事件驱动。简单点来说,是一个针对系统文件的事件管理器,可以高效管理大量网络链接下的数据并发。研发人员根据业务需要,通过事件管理器,监控对应文件描述符的读写事件。(详细解析请参考: 百度百科


🔥 文章来源:《epoll 多路复用 I/O工作流程

1.1. 事件结构

// epoll.h
typedef union epoll_data {
  void *ptr;
  int fd;
  uint32_t u32;
  uint64_t u64;
} epoll_data_t;

struct epoll_event {
  uint32_t events;   // epoll 事件
  epoll_data_t data; // 用户数据
} __EPOLL_PACKED;

epoll 事件描述
EPOLLIN可读。
EPOLLOUT可写。
EPOLLERR该文件描述符发生错误。
EPOLLHUP该文件描述符被挂断。

1.2. 操作接口

  • 创建 epoll 文件描述符。
int epoll_create(int size);
  • epoll 事件注册函数。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
op 操作事件描述
EPOLL_CTL_ADD注册新的 fd 到 epfd
EPOLL_CTL_MOD修改已经注册的 fd 的监听事件
EPOLL_CTL_DEL从 epfd 中删除一个 fd
  • 等待事件发生。
int epoll_wait(int epfd, struct epoll_event* events, int maxevents. int timeout);

2. 服务器使用流程

  • 服务器创建非阻塞 socket(server_fd)。
  • epoll_create 创建 epoll 事件驱动 (epoll_fd)。
  • epoll_ctl 监控 server_fd 的可读事件 EPOLLIN
  • 服务进程通过 epoll_wait 获取内核就绪事件处理。
  • 如果就绪事件是新连接,accept 为客户端新连接分配新的文件描述符 client_fd,设置非阻塞,然后 epoll_ctl 监控 client_fd 的可读事件 EPOLLIN
  • 如果就绪事件不是新连接,read 读取客户端发送数据进行逻辑处理。
  • 处理逻辑过程中需要 write 回复客户端,write 内容很大,超出了内核缓冲区,没能实时发送完成所有数据,需要下次继续发送;那么 epoll_ctl 监控 client_fd 的 EPOLLOUT 可写事件,下次触发事件进行发送。下次触发可写事件发送完毕后, epoll_ctl 删除 EPOLLOUT 事件。
  • 客户端关闭链接,服务端监控客户端 fd,如果 read == 0close 关闭对应 fd 从而完成四次挥手。

epoll 使用流程


3. 参考


你的点赞👍,是对作者最好的支持,谢谢!😸

<think>首先,用户的问题是:“I/O多路复用”,翻译成中文是“I/O多路复用”。我需要用中文回答问题。 我的回答必须包括: 1. 对问题的解释。 2. 在回答末尾,提出3-5个相关问题。 3. 相关问题必须以“§§相关问题§§”开头,且第一行完整输出这个短语。 4. 禁止换行分散,意思是相关问题部分要连贯,不要有多余的换行。 问题主题是I/O多路复用(I/O multiplexing)。我需要解释它是什么。 关键点: - I/O多路复用是一种技术,允许一个进程监视多个文件描述符(如套接字)以检查它们是否准备好进行I/O操作。 - 常见的实现包括select、poll、epoll(在Linux中)。 - 目的是高效处理多个I/O操作,避免阻塞或使用多线程的开销。 我的回答结构: - 先解释I/O多路复用的概念。 - 然后,简要描述其工作原理或常见用法。 - 最后,输出相关问题。 相关问题必须基于用户的问题和我的回答。用户的问题是“I/O多路复用”,所以我应该提出相关的后续问题,比如: 1. 常见的I/O多路复用模型有哪些? 2. 如何在不同操作系统上实现I/O多路复用? 3. I/O多路复用与多线程或多进程模型的区别是什么? 4. 在实际应用中,I/O多路复用的优缺点是什么? 5. 如何使用select、poll或epoll编写代码? 确保相关问题数量在3-5个。 最后,输出格式: - 回答内容。 - 然后,直接输出“§§相关问题§§”。 - 接着,列出问题,用数字或点号表示,如“1. ... 2. ...”。 从示例中,相关问题是用数字列表,如: 1. ··· 2. ··· 3. ··· 所以,我应该用类似格式。 现在,构建回答: - 开头:解释I/O多路复用。 - 中间:可能添加一个简单代码示例(但不是必须的,用户没有要求代码,但示例中有代码,所以我可以考虑添加一个简单的代码片段)。 - 结尾:相关问题。 用户的问题只有“I/O多路复用”,没有指定语言,但示例中有Python代码。所以,我可以添加一个简单的代码示例来展示select或epoll使用。 为了符合规则,回答必须用中文。 大纲回答: 1. 定义I/O多路复用。 2. 描述其目的和优势。 3. 简要说明常见模型。 4. 添加一个代码示例(可选)。 5. 然后,相关问题。 代码示例:使用Python的select模块。 例如: ```python import select import socket # 创建一个服务器套接字 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(('localhost', 8080)) server_socket.listen(5) # 输入列表,包含要监视的套接字 inputs = [server_socket] while True: # 使用select监视可读的套接字 readable, _, _ = select.select(inputs, [], []) for s in readable: if s is server_socket: # 新连接 client_socket, addr = server_socket.accept() inputs.append(client_socket) else: # 处理客户端数据 data = s.recv(1024) if data: # 处理数据 pass else: # 连接关闭 inputs.remove(s) s.close() ``` 然后,相关问题。 相关问题想法: 1. select、poll和epoll有什么区别? 2. 在哪些场景下应该使用I/O多路复用? 3. I/O多路复用如何处理高并发? 4. 如何避免I/O多路复用中的性能瓶颈? 5. 在Python中,除了select,还有哪些模块支持I/O多路复用? 确保3-5个。 最终输出: - 回答内容。 - “§§相关问题§§” - 1. ... 2. ... 3. ...</think>I/O多路复用(I/O Multiplexing)是一种高效处理多个输入/输出操作的网络编程技术,允许单个进程同时监视多个文件描述符(如套接字),并在其中任何一个准备好进行读写操作时通知进程。核心目的是避免阻塞式I/O或多线程的开销,提高系统并发性能。常见实现模型包括select、poll和epoll(Linux特有),它们通过系统调用实现非阻塞事件循环。例如,使用select模型可以同时监听多个套接字,当数据可读或可写时触发处理,减少资源消耗。基本工作流程如下: - 初始化:创建并注册要监视的文件描述符列表。 - 事件循环:调用select/poll/epoll等待事件发生(如数据到达)。 - 事件处理:遍历就绪的描述符并执行相应I/O操作。 - 重复循环:持续监听新事件。 在实际应用中,I/O多路复用常用于高并发服务器(如Web服务器或数据库),以处理数千个连接。优势包括减少线程切换开销、简化代码结构;劣势是编程复杂度较高,需处理事件循环细节。以下是一个简单Python代码示例,使用select实现TCP服务器: ```python import select import socket # 创建服务器套接字 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(('localhost', 8080)) server_socket.listen(5) inputs = [server_socket] # 监视列表 while True: readable, _, _ = select.select(inputs, [], []) # 等待可读事件 for s in readable: if s is server_socket: # 新连接 client_socket, addr = s.accept() inputs.append(client_socket) else: # 客户端数据可读 data = s.recv(1024) if data: print(f"收到数据: {data.decode()}") else: # 连接关闭 inputs.remove(s) s.close() ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值