目录
[一、IO 多路复用的定义和作用](#一、IO 多路复用的定义和作用)
[二、Linux 提供的 IO 模型](#二、Linux 提供的 IO 模型)
[三、IO 多路复用之 select](#三、IO 多路复用之 select)
[1.select 的处理流程](#1.select 的处理流程)
[2.select 相关函数](#2.select 相关函数)
[四、IO 多路复用之 epoll](#四、IO 多路复用之 epoll)
[1.epoll 的处理流程](#1.epoll 的处理流程)
[2.epoll 相关函数](#2.epoll 相关函数)
[2.1 创建 epoll 集合](#2.1 创建 epoll 集合)
[2.2 管理 FD(添加 / 删除)](#2.2 管理 FD(添加 / 删除))
[2.3 等待就绪事件](#2.3 等待就绪事件)
[五、select 与 epoll 的区别](#五、select 与 epoll 的区别)
在 Linux 网络编程中,IO 多路复用是处理高并发场景的核心技术之一。它让单线程 / 进程能同时监听多个 IO 对象(比如 socket、文件描述符),大幅提升程序的资源利用率。
一、IO 多路复用的定义和作用
- 定义:单线程 / 单进程同时监测多个文件描述符(FD),判断哪些可以执行 IO 操作的能力。
- 核心作用 :
- 用在 TCP Server 中,同时处理多个客户端请求;
- 对多个阻塞设备做 IO:哪个设备数据先就绪(可读 / 可写),就优先处理。
二、Linux 提供的 IO 模型
Linux 下常见的 IO 模型有 5 种,其中IO 多路复用是高并发场景的首选:
- 阻塞 IO(默认):IO 操作时阻塞线程,直到完成;
- 非阻塞 IO:不阻塞线程,但需轮询判断是否就绪;
- 信号驱动 IO(SIGIO):用得较少;
- 并行模型(进程 / 线程):资源开销大;
- IO 多路复用:select、poll、epoll。
三、IO 多路复用之 select
select 是 IO 多路复用的经典实现,核心是轮询检测 FD 集合。
1.select 的处理流程
- 创建 FD 集合(数组);
- 将需要监听的 FD 添加到集合;
- select 阻塞等待,轮询检测 FD 是否就绪;
- 遍历集合,找到就绪的 FD;
- 对就绪 FD 执行 read/write 操作;
- 注意 :每次检测后需手动清除集合的标志位(因为 select 会修改集合)。

2.select 相关函数
cpp
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
- **功能:**阻塞等待,检测集合中就绪的 FD;
- 参数:
- nfds:监听的最大 FD+1;
- readfds/writefds/exceptfds:读 / 写 / 异常 FD 集合;
- timeout:超时时间(NULL 表示一直阻塞);
- 辅助函数:
- FD_ZERO(fd_set *set):清空 FD 集合;
- FD_SET(int fd, fd_set *set):将 FD 加入集合;
- FD_CLR(int fd, fd_set *set):从集合中移除 FD;
- FD_ISSET(int fd, fd_set *set):判断 FD 是否在集合中。
四、IO 多路复用之 epoll
epoll 是 select 的 "加强版",专为高并发设计,核心是事件驱动 + 主动上报。
1.epoll 的处理流程
- 创建 epoll 集合(内核维护的二叉树结构);
- 将需要监听的 FD 添加到集合;
- epoll_wait 阻塞等待,由内核主动上报就绪 FD;
- 从返回的 rev 数组中直接获取就绪 FD;
- 对就绪 FD 执行读写操作。

2.epoll 相关函数
2.1 创建 epoll 集合
cpp
int epoll_create(int size);
- **功能:**创建 epoll 集合
- **参数:**size:指定集合的大小
- 返回值:
- >0:epoll 对应的文件描述符(epfd)
- -1:错误
2.2 管理 FD(添加 / 删除)
cpp
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
-
**功能:**向集合中添加或删除文件描述
-
参数:
-
size:指定集合的大小
-
op:
- EPOLL_CTL_ADD:添加描述描述符到集合
- EPOLL_CTL_DEL :从集合中删除文件描述符
-
fd:关心的文件描述符
-
event:监听的事件
*cppstruct epoll_event { uint32_t events; // 关心读(EPOLLIN),写(EPOLLOUT) epoll_data_t data; // 用户自定义数据,方便后期查找 };
-
-
返回值:
- 0:成功
- -1:错误
2.3 等待就绪事件
cpp
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
- **功能:**等待 io 事件的到来,阻塞函数
- 参数:
- epfd:需要检测的集合
- events:当有 io 事件到来时,存储准备(可读或可写)就绪的文件描述符数组
- maxevents:events 数组的大小
- timeout :超时值设置。 单位 ms(毫秒)(-1:阻塞版本)
- 返回值:
- >0:集合中准备就绪的文件描述符的个数
- 0:超时
- -1:错误
五、select 与 epoll 的区别
| 对比维度 | select | epoll |
|---|---|---|
| FD 数量限制 | 最多 1024 个 | 无限制(仅受系统资源约束) |
| 性能 | 随 FD 数量增加而下降(O (n) 轮询) | 不随 FD 数量变化(O (1) 主动上报) |
| 数据传递 | 内核 - 用户层多次拷贝 FD 集合 | 共享内存,无额外拷贝 |
| 返回结果 | 需遍历原始集合找就绪 FD | 直接返回就绪 FD 列表 |