Linux 核心 IO 模型深析
IO 是 Linux 系统性能的核心瓶颈之一,所有 IO 操作本质上都离不开'等待'与'拷贝'两个关键步骤。在五种经典 IO 模型中,非阻塞 IO 以'轮询'打破传统阻塞限制,多路转接 IO 凭'多文件描述符监听'实现高效等待,二者凭借独特的工作逻辑,成为高并发、低延迟场景的核心选择。
IO 介绍
现在我们知道所谓的输入和输出都是从下层的接收和发送缓冲区里面拿,数据的获取交给底层协议的通信,而这些读写接口如果没有拿到数据就会是——等待;如果有数据就需要——拷贝。
因此 IO 本质是:等待 + 拷贝的过程,根据数据的情况从传输层拷贝到应用层!如果想优化效率,大多都是合理运用等待的时长——非阻塞。
非阻塞 IO 模型
**特点:**一次操控一个文件描述符。
函数接口介绍
原型:
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */);
参数:
- **第一个参数:**要操作的文件描述符。
- **第二个参数:**操作命令,告诉
fcntl()要做什么。
| 命令 | 作用 | arg 说明 |
|---|---|---|
F_GETFL | 获取 fd 当前的状态 | 无需 arg(第三个参数省略),返回值为当前状态标志(整数) |
F_SETFL | 设置 fd 的当前的属性 | arg 传入新的状态标志(整数),仅能修改 O_APPEND、O_NONBLOCK(非阻塞)、O_ASYNC 等标志 |
- **第三个参数:**可选参数,当
cmd需要额外参数时传入。
返回值:
- 成功:根据
cmd不同返回不同结果。 - (非阻塞模式下:读写无数据时,立即返回 -1,且
errno设为EAGAIN或EWOULDBLOCK)。 - 失败:返回 -1,并设置
errno。
作用:对传入的文件描述符执行多种操作(查询 / 设置该文件描述符对应文件的属性)。
举例
现在我们的客户端是可以正常给服务端发送请求:服务端阻塞式的读。
现在我们调用 fcntl() 形成非阻塞式的读:对应读写不用一直阻塞也可以有返回值。
// 读取客户端内容
{
fc = (new_token, F_GETFL);
(fc == ) {
std::cout << << std::endl;
}
fc |= O_NONBLOCK;
((new_token, F_SETFL, fc) == ) {
();
();
}
buffer[max_buffer] = {};
() {
t = (new_token, buffer, (buffer) - , );
(t > ) {
std::cout << << buffer << std::endl;
} (t == ) {
std::cout << << std::endl;
;
} (t == ) {
(errno == EAGAIN || errno == EWOULDBLOCK) {
();
();
} {
std::cout << << std::endl;
;
}
}
}
}


