【Linux杂货铺】IO多路复用

目录

🌈前言🌈

📁 五种IO模型

 📂 阻塞IO

 📂 非阻塞IO

 📂 信号驱动IO

 📂 多路复用

 📂 异步IO

📁 非阻塞IO实现

📁 select

 📂 接口使用

 📂 缺点

📁 poll

 📂 接口使用

 📂 优缺点

📁 epoll

 📂 接口使用

 📂 底层原理

 📂 工作模式 ET vs LT

 📂 优点

📁 总结


🌈前言🌈

        本期【Linux杂货铺】,主要讲解什么是IO多路复用,通过了解IO模式,了解为什么要有多路复用,以及其他的IO模型,学习多路复用的3中模型。

        

📁 五种IO模型

 📂 阻塞IO

        在内核将数据准备好之前,系统调用会一直等待。默认是阻塞方式。

 📂 非阻塞IO

        如果内核还没有将数据准备好,系统调用会直接返回,并且返回EWOULDBLOCK错误码。此时,就需要特殊判错误码,究竟是异常错误,还是非阻塞IO。

        非阻塞IO常常需要循环式的读写这个文件描述符,这个过程叫做轮询,对CPU是一个巨大的浪费,只有在特定场景下才会使用。

 📂 信号驱动IO

        内核将数据准备好,使用SIGIO信号通知应用程序进行IO操作。

 📂 多路复用

        同时等待多个文件描述符的就绪状态,如果有一个或多个文件描述符事件触发,就会返回。

 📂 异步IO

        由内核在数据拷贝完成时,通知应用程序,上层只需要完成数据处理即可。但是异步IO往往伴随着代码逻辑复杂,难以理解,编程困难等问题。

        在IO过程中,需要经过两个步骤,1. 等待;2. 拷贝。等待的时间往往高于拷贝时间,因此提高IO效率,最核心的方法就是缩小等待时间。

        此外,同步和异步关注的消息通知机制

        同步,就是发出一个调用时,在没有得到结果之前,该调用就不返回。一旦调用返回,就得到返回值,即由调用者主动等待这个调用结果;

        异步,调用发出之后,这个调用会直接返回,没有返回结果,即一个异步调用发出后,调用者不会立刻得到结果,而是调用发出后,被调用者通过,信号等通知调用者,通过回调函数处理这个调用。

        阻塞和非阻塞关注的是程序等待调用结果时状态。

        阻塞调用指的是调用结果返回之前,当前线程会被挂起,调用线程只有在得到结果才会返回。

        非阻塞调用指的是不能立刻得到结果之前,该调用不会阻塞当前线程。

📁 非阻塞IO实现

        文件描述符默认都是阻塞的。使用fcntl系统调用可以修改文件描述为非阻塞。

#include <unistd.h>
#include <fcntl.h>int fcntl(int fd ,int cmd , ...);

fcntl函数有5种功能:

        1. 复制现有的描述符(cmd = F_DUPFD)

        2. 获得/设置文件描述符标记(cmd = F_GETFD 或 F_SETFD)

        3. 获得/设置文件状态标记(cmd = F_GETFL 或 F_SETFL)

        4. 获得/设置异步IO所有权(cmd = F_GETOWN或F_SETOWN)

        5. 获得/设置锁(cmd = F_GETLK,F_SETLK或F_SETLKW)

void SetNoBlock(int fd)
{int fl = fcntl(fd , F_GETFL);if(fl < 0){prror("fcntl");return ;}fcntl(fd , F_SETFL , fl | O_NONBLOCK);
}

📁 select

 📂 接口使用

include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set
*exceptfds, struct timeval *timeout);

        • 参数 nfds 是需要监视的最大的文件描述符值+1;

        • rdset,wrset,exset 分别对应于需要检测的可读文件描述符的集合, 可写文件描述符的集合及异常文件描述符的集合;

        • 参数 timeout 为结构体 timeval, 用来设置 select()的等待时间。timeout为NULL时,表示select会一直被阻塞,直到事件发生;timeout为0时,仅检测描述符集合的状态,然后立刻返回,并不会等待外部事件的发生;timeout为特定时间值,如果指定时间段内没有事件发生,select会超时返回。

        fd_set结构表示为1个位图,一个bit位表示要监视文件描述符。select系统调用的三个fd_set参数是输入输出型参数,输入表示要监听哪些描述符,输出表示哪些描述符事件就绪。


void FD_CLR(int fd, fd_set *set); // 用来清除描述词组 set 中相关fd的位int FD_ISSET(int fd, fd_set *set); // 用来测试描述词组 set 中相关fd的位是否为真void FD_SET(int fd, fd_set *set); // 用来设置描述词组 set 中相关fd的位void FD_ZERO(fd_set *set); // 用来清除描述词组 set 的全部位

        select系统调用返回值:执行成功返回文件描述符状态已改变的个数;如果返回值为0表示超时;如果返回-1,错误原因存在于errno。

        select系统调用常常搭配一个数组来使用。将需要监听的描述符添加至数组,通过遍历数组来给fd_set赋值。

 📂 缺点

        1. select函数,支持的文件描述符数量太小;

        2. select函数,每次都需要手动设置fd集合,使用不方便;

        3. 每次调用select都需要在内核遍历传递进来所有的fd,这个开销在fd很多时也很大。

        4. 每次调用select,都需要吧fd集合从用户态拷贝到内核态,这个开销在fd很多时很大。
 

📁 poll

 📂 接口使用


include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
// pollfd 结构
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};

        • fds 是一个 poll 函数监听的结构列表. 每一个元素中, 包含了三部分内容: 文件描述符, 监听的事件集合, 返回的事件集合.

        • nfds 表示 fds 数组的长度.

        • timeout 表示 poll 函数的超时时间, 单位是毫秒(ms)

        如果底层事件就绪,revents会被赋值。

 events和revents的取值:

        poll函数返回值小于0,表示出错;返回值等于0,表示poll等待超时;返回值小于0,表示由于poll由于文件描述符就绪而返回。 

 📂 优缺点

        1. poll没有描述符的数量限制;接口比select使用更方便,pollfd结构体包含了要监视的event和发生的revent,不在使用select输入输出型参数传递方式。

        2. 同select一样,poll返回后,需要遍历pollfd数组来获取就绪的描述符。

        3. poll需要把大量的pollfd结构体从用户态拷贝至内核态。

📁 epoll

 📂 接口使用

1. 创建epoll文件描述符(句柄)
int epoll_create(int size);2.操作epoll模型
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);3. 等待时间
int epoll_wait(int epfd , struct epoll_event* events,int maxevents , int timeout);

op参数表示动作,用3个宏来表示:

        • EPOLL_CTL_ADD: 注册新的 fd 到 epfd 中;

        • EPOLL_CTL_MOD: 修改已经注册的 fd 的监听事件;

        • EPOLL_CTL_DEL: 从 epfd 中删除一个 fd;

uint32_t events可以是一下几个宏的集合:

        • EPOLLIN : 表示对应的文件描述符可以读 (包括对端 SOCKET 正常关闭);

        • EPOLLOUT : 表示对应的文件描述符可以写;

        • EPOLLPRI : 表示对应的文件描述符有紧急的数据可读 (这里应该表示有带外数据到来);

        • EPOLLERR : 表示对应的文件描述符发生错误;

        • EPOLLHUP : 表示对应的文件描述符被挂断;

        • EPOLLET : 将 EPOLL 设为边缘触发(Edge Triggered)模式, 这是相对于水平触发(Level Triggered)来说的.

        • EPOLLONESHOT: 只监听一次事件, 当监听完这次事件之后, 如果还需要继续监听这个 socket 的话, 需要再次把这个 socket 加入到 EPOLL 队列里.

        epoll_wait系统调用会将底层已经就绪的事件拷贝至数组中,系统调用返回值就是已经就绪的事件数量n,只需要遍历数组前n个元素即可。

 📂 底层原理

        epoll模型中,节点采用了与类型无关的数据结构,即一个节点可以被连入到不同的数据结构中,既可以在红黑树中,也可以在就绪队列中。

        当节点既在红黑树中中,又在就绪队列中,就表示该节点监视的文件描述中有事件触发。

 📂 工作模式 ET vs LT

        水平触发(LT):epoll默认状态下就是LT模式。当epoll检测到事件就绪,如果没有处理,或者处理不完全,再次调用epoll_wait时会立即返回并通知事件就绪,直到事件被处理完成,如缓冲区上所有数据被处理完成,epoll_wait才不会立刻返回。支持阻塞读写或非阻塞读写。

        边缘触发(ET):epoll检测到有事件就绪,必须立刻处理。如果没有处理,或者处理不完全,下次调用epoll_wait不会再通知,而是等到有新的数据到来,事件再次就绪,再次通知上层。即事件就绪后,只有一次处理机会。ET模式比LT模式性能更高,Nginx默认采用ET模式。ET模式只支持非阻塞读写。

        ET模式的epoll,需要将文件描述符设置为非阻塞,这不是接口上的要求,而是“工程实践”上的要求。

        如果面对下面这种情况,ET模式采用阻塞读取是会出现问题的:

• 服务器只读到 1k 个数据, 要 10k 读完才会给客户端返回响应数据.

• 客户端要读到服务器的响应, 才会发送下一个请求

• 客户端发送了下一个请求, epoll_wait 才会返回, 才能去读缓冲区中剩余的数据

        因此,为了解决上述问题,需要将ET模式改为非阻塞轮询式读取底层数据,一次将数据全部读取完毕。

 📂 优点

        1. 接口使用方便。

        2. 数据拷贝轻量。

        3. 事件回调机制,避免了使用遍历,而是使用回调函数的方式,将就绪的文件描述符结构加入就绪队列中。

        4. 没有数量限制。

📁 总结

        以上,就是本期【Linux杂货铺】的主要内容了,主要讲解了五种IO模型,重点讲解了select,epoll接口,学习了epoll底层原理,以及epoll的工作模式,了解了poll接口,其中epoll是尤为重要的多路复用接口。

        如果感觉本期内容对你有帮助,欢迎点赞,关注,收藏Thanks♪(・ω・)ノ

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

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

相关文章

Kafka 的一些问题,夺命15连问

kafka-中的组成员 kafka四大核心 生产者API 允许应用程序发布记录流至一个或者多个kafka的主题&#xff08;topics&#xff09;。 消费者API 允许应用程序订阅一个或者多个主题&#xff0c;并处理这些主题接收到的记录流 StreamsAPI 允许应用程序充当流处理器&#xff08;s…

ANNOVAR下载

1.官网 https://annovar.openbioinformatics.org/en/latest/user-guide/startup/ 都填英文 要不然会报错 tar -xzvf annovar.latest.tar.gztree . ├── annotate_variation.pl ├── coding_change.pl ├── convert2annovar.pl ├── example │ ├── ex1.avinput…

集群架构中Lua脚本的限制以及出现的报错

&#x1f680; 博主介绍&#xff1a;大家好&#xff0c;我是无休居士&#xff01;一枚任职于一线Top3互联网大厂的Java开发工程师&#xff01; &#x1f680; &#x1f31f; 在这里&#xff0c;你将找到通往Java技术大门的钥匙。作为一个爱敲代码技术人&#xff0c;我不仅热衷…

大语言模型:解锁自然语言处理的无限可能

0.引言 在当今的科技时代&#xff0c;自然语言处理技术正以前所未有的速度发展&#xff0c;语言大模型作为其中的核心力量&#xff0c;对各个领域产生了深远的影响。本文旨在探讨语言大模型的发展历程、核心技术以及广泛的应用场景&#xff0c;以帮助读者更好地理解这一前沿技…

MATLAB实现智能水滴算法(Intelligent Water Drops Algorithm, IWDA)

1.智能水滴算法介绍 智能水滴算法&#xff08;Intelligent Water Drops Algorithm&#xff0c;IWDA&#xff09;是一种基于水滴特性的智能优化算法&#xff0c;它借鉴了水滴在自然界中的运动和形态变化规律&#xff0c;通过模拟水滴的形成、发展和消亡过程&#xff0c;实现问题…

【计网】基于TCP协议的Echo Server程序实现与多版本测试

目录 前言&#xff1a; 1、InitServer类的实现 1.1. 创建流式套接字 1.2. bind 绑定一个固定的网络地址和端口号 1.3.listen监听机制 1.4.完整代码 2. 循环接收接口与服务接口 2.1.accept函数讲解 讲个商场拉客的故事方便我们理解&#xff1a; 2.2.服务接口实现 3.服…

easyexcel实现自定义的策略类, 最后追加错误提示列, 自适应列宽,自动合并重复单元格, 美化表头

easyexcel实现自定义的策略类, 最后追加错误提示列, 自适应列宽,自动合并重复单元格, 美化表头 原版表头和表体字体美化自动拼接错误提示列自适应宽度自动合并单元格使用Easyexcel使用poi导出 在后台管理开发的工作中,离不开的就是导出excel了. 如果是简单的导出, 直接easyexce…

边缘计算的学习

文章目录 概要何为边缘计算&#xff1f;现阶段&#xff0c;企业使用边缘计算相对云计算 整体架构流程边缘网络组件边缘计算与云安全 研究方向结合引用 概要 edge 何为边缘计算&#xff1f; 边缘计算&#xff08;英语&#xff1a;Edge computing&#xff09;&#xff0c;是一种…

SpringBoot在城镇保障性住房管理中的应用

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理城镇保障性住房管理系统的相关信息成为必然…

算法|牛客网华为机试41-52C++

牛客网华为机试 上篇&#xff1a;算法|牛客网华为机试21-30C 文章目录 HJ41 称砝码HJ42 学英语HJ43 迷宫问题HJ44 SudokuHJ45 名字的漂亮度HJ46 截取字符串HJ48 从单向链表中删除指定值的节点HJ50 四则运算HJ51 输出单向链表中倒数第k个结点HJ52 计算字符串的编辑距离 HJ41 称砝…

粒子群优化双向深度学习!PSO-BiTCN-BiGRU-Attention多输入单输出回归预测

粒子群优化双向深度学习&#xff01;PSO-BiTCN-BiGRU-Attention多输入单输出回归预测 目录 粒子群优化双向深度学习&#xff01;PSO-BiTCN-BiGRU-Attention多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现PSO-BiTCN-BiGRU-Attention粒子…

「Mac玩转仓颉内测版1」入门篇1 - Cangjie环境的搭建

本篇详细介绍在Mac系统上快速搭建Cangjie开发环境的步骤&#xff0c;涵盖VSCode的下载与安装、Cangjie插件的离线安装、工具链的配置及验证。通过这些步骤&#xff0c;确保开发环境配置完成&#xff0c;为Cangjie项目开发提供稳定的基础支持。 关键词 Cangjie开发环境搭建VSC…

协程6 --- HOOK

文章目录 HOOK 概述链接运行时动态链接 linux上的常见HOOK方式修改函数指针用户态动态库拦截getpidmalloc 第一版malloc 第二版malloc/free通过指针获取到空间大小malloc 第三版strncmp 内核态系统调用拦截堆栈式文件系统 协程的HOOK HOOK 概述 原理&#xff1a;修改符号指向 …

ResNet 残差网络 (乘法→加法的思想 - 残差连接是所有前沿模型的标配) + 代码实现 ——笔记2.16《动手学深度学习》

目录 前言 0. 乘法变加法的思想 1. 函数类 2. 残差块 (讲解代码) QA: 残差这个概念的体现&#xff1f; 3. ResNet模型 (代码讲解) 补充&#xff1a;更多版本的ResNet 4. 训练模型 5. 小结 6. ResNet的两大卖点 6.1 加深模型可以退化为浅层模型 6.2 用加法解决梯度消…

iphone怎么删除重复的照片的新策略

Phone用户常常面临存储空间不足的问题&#xff0c;其中一个主要原因是相册中的重复照片。这些重复项不仅占用了大量的存储空间&#xff0c;还会影响设备的整体性能。本文将向您展示iphone怎么删除重复的照片的方法&#xff0c;包括一些利用工具来自动化这个过程的创新方法。 识…

软件缺陷等级评定综述

1. 前言 正确评估软件缺陷等级&#xff0c;在项目的生命周期中有着重要的作用&#xff1a; 指导缺陷修复的优先级和资源分配 在软件开发和维护过程中&#xff0c;资源&#xff08;包括人力、时间和资金&#xff09;是有限的。通过明确缺陷的危险等级&#xff0c;可以帮助团队合…

【Pikachu】Cross-Site Scripting跨站脚本攻击实战

只管把目标定在高峰&#xff0c;人家要笑就让他去笑&#xff01; 1.XSS&#xff08;跨站脚本&#xff09;概述 XSS&#xff08;跨站脚本&#xff09;概述 Cross-Site Scripting 简称为“CSS”&#xff0c;为避免与前端叠成样式表的缩写"CSS"冲突&#xff0c;故又称…

【SpringBoot】 黑马大事件笔记-day2

目录 用户部分 实体类属性的参数校验 更新用户密码 文章部分 规定josn日期输出格式 分组校验 上期回顾&#xff1a;【SpringBoot】 黑马大事件笔记-day1 用户部分 实体类属性的参数校验 对应的接口文档&#xff1a; 基本信息 请求路径&#xff1a;/user/update 请求方式&#…

大数据面试题--kafka夺命连环问

1、kafka消息发送的流程&#xff1f; 在消息发送过程中涉及到两个线程&#xff1a;一个是 main 线程和一个 sender 线程。在 main 线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给双端队列&#xff0c;sender 线程不断从双端队列 RecordAccumulator 中拉取…

QT信号和槽与自定义的信号和槽

QT信号和槽与自定义的信号和槽 1.概述 这篇文章介绍下QT信号和槽的入门知识&#xff0c;通过一个案例介绍如何创建信号和槽&#xff0c;并调用他们。 2.信号和槽使用 下面通过点击按钮关闭窗口的案例介绍如何使用信号和槽。 创建按钮 在widget.cpp文件中创建按钮代码如下 …