主要还是 epool,IO 多路复用
| 阶段 | 阻塞 IO(BIO) | 非阻塞 IO(NIO) | 多路复用 IO | 信号驱动 IO | 异步 IO(AIO) |
|---|---|---|---|---|---|
| 等待数据就绪 | 阻塞 | 非阻塞(轮询) | 阻塞 | 非阻塞 | 非阻塞 |
| 数据从内核拷贝到用户态 | 阻塞 | 阻塞 | 阻塞 | 阻塞 | 非阻塞 |
| 核心特征 | 全程阻塞 | 轮询耗资源 | 单进程监控多 FD | 信号回调 | 全程非阻塞 |


## **IO模型核心概念**
- 定义:描述程序与I/O操作的交互方式,影响性能、可扩展性、资源利用率
- 核心阶段:等待读就绪(数据到网卡→内核缓冲区)、读取数据(内核缓冲区→用户缓冲区)
- 关键区分:阻塞/非阻塞针对「等待读就绪阶段」
## **五大IO模型详解**
- 阻塞式IO
- 核心特征:两阶段均阻塞(accept、read均阻塞)
- 伪代码实现:单线程循环,accept建立连接后直接read+处理
- 优缺点:简单直接,但无法并发处理多个连接
- 非阻塞式IO
- 分类:伪非阻塞(多线程,子线程read仍阻塞)、真正非阻塞(操作系统提供非阻塞read)
- 核心特征:等待读就绪阶段非阻塞(未就绪返回-1),读取数据阶段仍阻塞
- 关键能力:单线程管理多个文件描述符
- 伪代码实现:主线程存连接,异步线程轮询非阻塞read
- IO多路复用
- 核心思路:将连接检测交给操作系统,减少系统调用
- 实现方式
- select:BitsMap存储文件描述符,默认最大1024个,需双向拷贝+两次遍历
- poll:动态链表存储,突破1024限制,仍需双向拷贝+两次遍历
- epoll:红黑树+事件链表,优化三大问题(无需重复拷贝、事件唤醒替代遍历、仅返回就绪描述符)
- epoll关键特性:支持LT(水平触发,默认)和ET(边缘触发)
- LT:数据未读完持续通知
- ET:仅通知一次,需一次性读完数据
- 伪代码实现:epoll_create创建对象,epoll_ctl添加连接,epoll_wait获取就绪连接
- 信号驱动IO
- 核心特征:发起读请求后,等待读就绪事件通知,再读取数据
- 异步IO
- 核心特征:发起读请求后,等待操作系统读取完成通知,完全交由OS实现
## **模型演进与关系**
- 演进逻辑:从用户态优化到内核态支持,逐步将更多功能交给操作系统
- 阻塞IO → 多线程伪非阻塞 → 真正非阻塞IO(用户态轮询) → IO多路复用(内核态检测) → 异步IO(内核态全程处理)
- 核心优化点:减少系统调用、提升单线程管理多连接能力、降低资源消耗
## **关键对比**
- 阻塞IO vs 非阻塞IO:等待阶段是否阻塞
- select/poll vs epoll:文件描述符存储方式、检测机制、拷贝效率
- 水平触发 vs 边缘触发:epoll的事件通知频率(持续通知vs单次通知)
- IO多路复用 vs 异步IO:前者需主动读取数据,后者OS完成读取后通知

在阻塞式I/O模型中,应用程序在从调用recvfrom开始到它返回有数据报准备好这段时间是阻塞的,recvfrom返回成功后,应用进程开始处理数据报

listenfd = socket(); // 打开一个网络通信套接字
bind(listenfd); // 绑定
listen(listenfd); // 监听
while(1) {
connfd = accept(listenfd); // 阻塞 等待建立连接
int n = read(connfd, buf); // 阻塞 读数据
doSomeThing(buf); // 处理数据
close(connfd); // 关闭连接
}