主要还是 epool,IO 多路复用

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

image.png

image.png

## **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完成读取后通知

序言

服务端网络请求

image.png

IO模型

阻塞式 IO

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

image.png

服务端如何处理客户端请求

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