【Linux】I/O多路复用模型 select、poll、epoll

创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡>𖥦<)!!
主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步!
🔥Linux系列专栏:Linux基础 🔥

给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ

在这里插入图片描述


目录

    • 多路:
    • 复用:
  • 一、select 模型
  • 二、poll 模型
  • 三、epoll 模型
    • 水平触发模式 EPOLLLT
    • 边缘触发模式 EPOLLET
    • 示例

在监听 socket 时,需要分配多个线程/进程维护多个 socket 连接,I/O 多路复用技术就是用来使用一个进程来监听维护多个 socket 连接

多路:

I/O 状态:可读、可写

复用:

使用一个线程/进程监听处理 I/O 事件,复用多个 socket 请求


一、select 模型

select 原理:

  • 1.创建一个文件描述符集合 fd_set set 0 不监听 1 监听

  • 2.设置文件描述符的状态

    • FD_ZERO(&set); 初始化监听集合,将位码初始化为 0
    • FD_SET(int sockfd,&set); 将 sockfd 在集合中对应的位设置成 1
    • FD_CLR(int sockfd,&set); 将 sockfd 在集合中对应的位设置成 0
    • int code = FD_ISSET(int sockfd,&set); 返回 sockfd 在文件描述符集合中的位码
  • 3.调用 select 函数,传入文件描述符集合 set


select 函数:

#include <sys/select.h>
#include <unistd.h>int ready = select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* errorfds,struct timeval* timeout);

参数:

  • nfds: 需要监视的最大文件描述符值加 1
  • readfds:监听读事件,设为 NULL 不监听
  • writefds:监听写事件,设为 NULL 不监听
  • errorfds:异常事件
  • timeout:阻塞时间,设为 NULL 为阻塞监听,定义 timeval 结构体将成员设置为 0 为非阻塞。定时阻塞支持微妙级别定时

返回值:返回就绪的 socket 数量

select 函数会将整个文件描述符集合 set 拷贝到内核中,让内核检查是否有读/写事件,内核遍历文件描述符集合,
如果有事件发生,内核将对应的 socket 标记位可读/可写,然后将整个文件描述符集合 set 拷贝回用户空间,用户再遍历文件描述符集合找到就绪的 socket 进行后续处理


select 的缺点:

  • 1.Linux 平台受最大文件描述符数量限制,select 的最大监听数为 1024
  • 2.select 监听就绪后只返回就绪的数量,需要用户遍历找到就绪的 socket
  • 3.监听集合会在监听到就绪后被修改,需要用户自行分离传入传出设置
  • 4.轮询监听,轮询数量大, CPU 处理性能下降
  • 5.拷贝和挂载开销大
  • 6.设置监听不灵活,无法对不同的 socket 设置不同的监听类型

二、poll 模型

poll 监听事件种类更丰富,对监听和就绪数组进行了传入传出分离

poll 不受最大文件描述符数量限制,支持用户自定义长度结构体数组作为集合

#include <poll.h>int ready = poll(struct pollfd* fds, int nfds, int timeout);

参数:

  • fds:监听数组
    • struct pollfd listen_array[4096]; //监听数组
    • listen_array[0].fd = sockfd; //监听 sockfd,-1 取消监听
    • listen_array[0].events = POLLIN|POLLOUT|POLLERR; //设置监听事件
    • listen_array[0].revents; //如果监听的 socket 就绪,系统将就绪事件传到 revents 中
  • nfds:监听数组大小
  • timeout:阻塞时间,-1 为阻塞监听,0 为非阻塞。>0 定时阻塞 只支持毫妙级定时

poll 的缺点

  • 1.轮询监听,轮询数量大, CPU 处理性能下降
  • 2.拷贝和挂载开销大
  • 3.只有特定的 Linux 版本才能使用

三、epoll 模型

结合了 select 和 poll 的优势

创建监听树(创建于内核中,使用红黑树):

#include <sys/epoll.h>
int epfd = epoll_create(int size);

参数:size 为监听数量。返回值:指向监听树的描述符。


监听树节点

struct epolevent node;
node.data.fd = sockfd;
node.events = EPOLLIN|EPOLLOUT|EPOLLERR;

epoll 监听到就绪直接返回就绪节点,用户遍历处理这些就绪 socket 即可


向监听树中添加节点:

epoll_ctl(int epfd,EPOLL_CTL_ADD,int sockfd,struct epollevent* node);

在监听树中删除节点:

epoll_ctl(int epfd,EPOLL_CTL_DEL,int sockfd,NULL);

修改监听树中的节点(修改监听的事件):

epoll_ctl(int epfd,EPOLL_CTL_MOD,int sockfd,&node);

监听事件发生:

int ready = epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);

参数:

  • epfd:监听树
  • events:监听事件数组
  • maxevents:最大就绪数大小
  • timeout:阻塞时间,-1 为阻塞监听,0 为非阻塞。>0 定时阻塞

epoll 的优点:

  • 没有监听数量限制,不用担心轮询问题
  • epoll 使用了事件驱动的方式,监听集合在内核层,避免了每次调用时的重复设置和遍历操作。内核会将就绪的文件描述符直接返回
  • 监听事件种类更丰富,可以对不同的 socket 设置不同的事件监听,对监听和就绪数组进行了传入传出分离


水平触发模式 EPOLLLT

  • 当可读或可写事件发生时,epoll 会持续通知用户处理直到用户处理。
  • 以在任何时候处理这些通知,不必立即响应
  • 水平触发适用于处理数据量较大或需要缓冲数据的情况,因为可以确保用户不会错过任何数据

多个事件同时发生可能导致重复处理,可以使用 EPOLLONESHOT设置为只触发一次通知


边缘触发模式 EPOLLET

  • 当可读或可写事件发生时,epoll 会立即通知(只会通知 1 次)
  • 应用程序需要在收到通知后立即处理相应的 I/O 事件,否则可能会丢失事件
  • 边缘触发适用于处理大量并发连接且数据量较小的情况,可以减少不必要的系统调用和上下文切换。

边缘触发模式一般和非阻塞 I/O 搭配使用,直到系统调用(如 read 和 write)返回错误,错误类型为 EAGAIN 或 EWOULDBLOCK


示例

    //创建监听树并将serversock设置监听读事件if((epfd = epoll_create(EPOLL_MAX)) == -1){perror("epoll_initializer: create epoll tree failed");}struct epoll_event node;node.data.fd = sockfd;node.events = EPOLLIN;//添加节点epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&node);int readycode;struct epoll_event readyarray[EPOLL_MAX];int i = 0;int flag = 1;while(flag){if((readycode = epoll_wait(epfd,readyarray,EPOLL_MAX,-1)) == -1){perror("epoll_wait failed");}else{i = 0;//根据readycode就绪数量处理就绪while(readycode){//判断就绪if (readyarray[i].data.fd == server_sockfd){//server sock ready//添加tcp连接任务}else{//client sock ready//添加响应处理任务}--(readycode);++i;}}}

在这里插入图片描述

大家的点赞、收藏、关注将是我更新的最大动力! 欢迎留言或私信建议或问题。
大家的支持和反馈对我来说意义重大,我会继续不断努力提供有价值的内容!如果本文哪里有错误的地方还请大家多多指出(●'◡'●)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/30916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多模块存储器

随着计算机技术的发展&#xff0c;处理的信息量越来越多&#xff0c;对存储器的速度和容量要求也越来越高&#xff1b;而且随着CPU性能的不断提高、IO设备数量不断增加&#xff0c;导致主存的存取速度已经称为了整个计算机系统的性能瓶颈。这就要求我们必须提高主存的访问速度。…

令人震撼的人类智慧的科学领域-AI技术

AI&#xff0c;全称为人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;是一门致力于让机器模仿人类智慧的科学领域。其核心技术涵盖了机器学习、自然语言处理、计算机视觉及专家系统等多个方面。AI旨在开发能够感知环境、进行逻辑推理、自主学习并做出决策…

【VMware】VMware虚拟机安装_配置_使用教程

一、准备工作 1、下载VMware软件&#xff1a;访问VMware官方网站&#xff0c;下载适合你操作系统的VMware Workstation Pro安装包。 下载地址&#xff1a;VMware Desktop Hypervisors for Windows, Linux, and Mac 2、准备操作系统镜像文件&#xff1a;根据你想要在虚拟机中安…

红黑树(数据结构篇)

数据结构之红黑树 红黑树(RB-tree) 概念&#xff1a; 红黑树是AVL树的变种&#xff0c;它是每一个节点或者着成红色&#xff0c;或者着成黑色的一棵二叉查找树。对红黑树的操作在最坏情形下花费O(logN)时间&#xff0c;它的插入操作使用的是非递归形式实现红黑树的高度最多是…

thread model线程模型

Concurrency并发 vs. Parallelism执行 Many-to-One GNU Portable Threads 多对一即多个用户线程映射到单个内核线程 该模式用的少 一个线程阻塞会导致所有线程阻塞 多线程可能无法在多核系统上并行运行&#xff0c;因为同一时间内核中可能只有一个线程 Concurrent executio…

探索FlowUs息流:个人和团队知识管理解决方案|FlowUs稳定保障你的笔记安全无忧

FlowUs息流&#xff1a;稳定运营保障你的笔记安全无忧 在知识管理工具的选择上&#xff0c;稳定性是用户最关心的问题之一。FlowUs息流以其稳定的运营记录&#xff0c;为用户提供了一个可靠的工作环境。我们深知&#xff0c;一个知识管理平台的稳定性直接影响到团队的生产力和…

3ds MAX 2024版资源包下载分享 3ds Max三维建模软件资源包下载安装

3DSMAX凭借其强大的功能和广泛的应用领域&#xff0c;吸引了无数创作者的青睐。 在游戏制作领域&#xff0c;3DSMAX展现出了无可比拟的优势。从细腻的角色建模到宏大的场景搭建&#xff0c;再到逼真的动画效果和渲染&#xff0c;它都能轻松应对&#xff0c;为游戏世界注入了生动…

“开放”的大模型到底有多“开放”?!

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型重新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则…

java面向对象(上)

一.面向对象与面向过程 1.面向过程 面向过程(procedure Oriented Programming),简称POP,主要思想就是将问题分解成一个个步骤去解决,把这个步骤称为函数. 典型语言:C语言 优点:可以大大简化代码 缺点:当代码量过大时,不方便维护 2.面向对象 面向对象(Object Oriented Pr…

Harbor 源码编译arm版本镜像

1. 先准备一个国外的arm服务器&#xff0c;&#xff08;使用国内的也行&#xff0c;只是有时候下载依赖会断&#xff0c;需要科学上网&#xff09; 2. git clone harbor的源码包&#xff0c;切换到要编译的分支 3. 修改harbor/Makefile Makefile里面的这些字段设置为true&…

四川财谷通信息技术抖音小店信誉之选,购物新体验

在当今数字化浪潮的推动下&#xff0c;电商平台的兴起为人们的生活带来了极大的便利。而在众多电商平台中&#xff0c;抖音小店以其独特的社交属性和便捷的购物体验&#xff0c;逐渐赢得了消费者的青睐。四川财谷通信息技术有限公司旗下的抖音小店&#xff0c;更是凭借其可靠的…

记录SpringBoot启动报错解决

记录SpringBoot启动报错解决 报错现场 Failed to configure a DataSource: url attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class Action: Consider the following:If you want an embedde…

33.获取入口点

上一个内容&#xff1a;32.双击列表启动目标游戏 前置知识 25.入口点注入&#xff08;查看pe头&#xff09;、32.双击列表启动目标游戏 以它的代码为基础进行修改 效果图&#xff1a; 代码实现&#xff1a;原理通过读文件流的方式把文件加载到内存中然后解析pe结构 void CWnd…

uniapp 实人认证

首先Dcloud创建云服务空间&#xff0c;开启一键登录并充值 下一步 1. 右键项目 》 创建uniCloud云开发环境 》右键uniCloud》关联云服务空间 2. cloudfunctions右键 新建云函数&#xff0c;任意命名&#xff08;例&#xff1a;veify&#xff09;&#xff0c;然后右键项目》管…

Python 基础:异常

目录 一、异常概念二、处理异常2.1 抛出异常2.2 使用 try-except 代码块2.3 使用 try-except-else 代码块2.4 静默失败 三、总结 遇到看不明白的地方&#xff0c;欢迎在评论中留言呐&#xff0c;一起讨论&#xff0c;一起进步&#xff01; 本文参考&#xff1a;《Python编程&a…

Vite文件目录结构介绍

我们通过命令create-vite shop-admin基于Vite创建vue3项目后&#xff0c;其默认的文件目录结构如下&#xff1a; shop-admin ├─ index.html ├─ package-lock.json ├─ package.json ├─ public │ └─ vite.svg ├─ src │ ├─ App.vue │ ├─ assets │ │ └…

C++多重继承,虚基类与友元

一.多重继承 就是一个类继承多个基类&#xff1b; class <派生类名>&#xff1a;<派生方式1><基类名1>,<派生方式n><基类名n> class Derived:public:Base1,public:Base2 上述形式&#xff1a;基类之间由逗号隔开&#xff0c;且必须指明继承方式…

【Python绘画】气球祝福节日快乐

本文收录于 《一起学Python趣味编程》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、代码示例三、知识点梳理四、总结 一、前言 本文介绍如何使用Python的海龟画图工具turtle&#…

示例:WPF中DataGrid简单设置合并列头

一、目的&#xff1a;应用DataGridTemplateColumn列模板&#xff0c;去拆分列头和单元格布局的方式设置列头合并样式 二、实现 效果如下 三、环境 VS2022 四、示例 应用DataGridTemplateColumn自定义列头信息和单元格信息 <DataGrid AutoGenerateColumns"False"…

【机器学习】线性回归:从基础到实践的深度解析

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 线性回归&#xff1a;从基础到实践的深度解析引言一、线性回归基础1.1 定义与目…