Linux网络编程——IO多路复用

目录

[一、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 操作的能力。
  • 核心作用
    1. 用在 TCP Server 中,同时处理多个客户端请求;
    2. 对多个阻塞设备做 IO:哪个设备数据先就绪(可读 / 可写),就优先处理。

二、Linux 提供的 IO 模型

Linux 下常见的 IO 模型有 5 种,其中IO 多路复用是高并发场景的首选:

  1. 阻塞 IO(默认):IO 操作时阻塞线程,直到完成;
  2. 非阻塞 IO:不阻塞线程,但需轮询判断是否就绪;
  3. 信号驱动 IO(SIGIO):用得较少;
  4. 并行模型(进程 / 线程):资源开销大;
  5. IO 多路复用:select、poll、epoll。

三、IO 多路复用之 select

select 是 IO 多路复用的经典实现,核心是轮询检测 FD 集合

1.select 的处理流程

  1. 创建 FD 集合(数组);
  2. 将需要监听的 FD 添加到集合;
  3. select 阻塞等待,轮询检测 FD 是否就绪;
  4. 遍历集合,找到就绪的 FD;
  5. 对就绪 FD 执行 read/write 操作;
  6. 注意 :每次检测后需手动清除集合的标志位(因为 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 的处理流程

  1. 创建 epoll 集合(内核维护的二叉树结构);
  2. 将需要监听的 FD 添加到集合;
  3. epoll_wait 阻塞等待,由内核主动上报就绪 FD;
  4. 从返回的 rev 数组中直接获取就绪 FD;
  5. 对就绪 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:监听的事件
      *

      cpp 复制代码
      struct 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 列表
相关推荐
xiaoye-duck12 分钟前
《Linux系统编程》Linux 系统多线程(五):<线程同步与互斥>线程互斥(上):从条件变量到生产者消费者模型详解
linux·线程
多巴胺梦想家17 分钟前
06 代数系统:运算背后的结构之美
网络·拓扑学
小柯南敲键盘44 分钟前
图片翻译API接入与自动化实现指南
运维·python·自动化
小锋学长生活大爆炸1 小时前
【福利】最新免费领取云服务器和虚拟主机攻略
网络·github
952362 小时前
Docker - 基础
运维·后端·docker·容器
Promise微笑2 小时前
智能激光清障仪选型指南:高效运维与安全保障的关键考量
运维·安全
8125035332 小时前
第 60 篇:IP选项:那些被遗忘的功能
网络·tcp/ip·智能路由器
Code_Ignis2 小时前
docker国内可用源(持续维护)
运维·docker·容器
一叶龙洲2 小时前
向日葵远程Ubuntu,支持隐私屏
linux·运维·ubuntu
IT小盘3 小时前
04-大模型流式输出原理-SSE与Python实现
开发语言·网络·人工智能·python