Linux多路转接select,poll

文章目录

目录

文章目录

一、五种IO模型

1.阻塞IO:

2.非阻塞IO

3.信号驱动IO

4.IO多路转接

5.异步IO

二、高级IO的一些重要概念

1.同步通信和异步通信

2.阻塞和非阻塞

三、其他高级IO

四、非阻塞IO

1.fctl函数

2.实现setNoBlock函数,将文件描述符设置为非阻塞

3.轮询方式读取标准输入

五、IO多路转接之select

1.初始select

2.select函数原型

3.理解select执行过程

4.select的特点

5.select的缺点

6.select使用示例:检测标准输入输出

7.select使用实例

六、IO多路转接之poll

1.poll函数接口

2.参数说明

3.返回结果

4.poll的优点

5.poll的缺点

6.poll使用实例:使用poll监控标准输入

总结


一、五种IO模型

1.阻塞IO:

在内核将数据准备好之前,系统调用会一直等待。所有的套接字,默认都是阻塞方式。阻塞是最常见的IO模型。

2.非阻塞IO

如果内核还未将数据准备好,系统调用仍然会直接返回,并返回EWOULDBLOCK错误码。非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为轮询。这对cpu来说是较大的浪费,一般只有特定的场景下才使用。

3.信号驱动IO

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

4.IO多路转接

虽然从图上看和阻塞IO类似,实际上最核心在于IO多路转接能够同时等待多个文件描述符的就绪状态。

5.异步IO

由内核在数据拷贝完成时,通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据)

在任何IO过程中,都包含两个步骤,第一是等待,第二是拷贝。而且在实际的应用场景中,等待消耗的时间往往都高于拷贝的时间,让IO高效,最核心的办法就是让等待的时间尽量减少。

二、高级IO的一些重要概念

1.同步通信和异步通信

同步和异步关注的是消息通信机制

  • 同步,就是在发出一个调用的时候,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到了返回值。换句话说,就是由调用者主动等待这个调用的结果
  • 异步则相反,调用在发出后,这个调用结果就直接返回,所以没有返回结果。换句话说,当一个异步调用发出后,调用者不会立刻得到返回结果;而是在调用发出后,被调用者通过状态、通知来通知调用者,或者通过回调函数处理这个调用

在多进程多线程的时候,也有提到同步和互斥。这里的是完全不同的概念。

进程/线程同步也是进程/线程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系,尤其是在访问临界资源的时候。

2.阻塞和非阻塞

阻塞和非阻塞关注的是等待调用结果(消息,返回值)时的状态

  • 阻塞调用的指调用结果返回之前,当前线程会被挂起,调用线程只有在得到结果之后才会返回。
  • 非阻塞调用是指在不能立刻得到结果之前,该调用者不会阻塞当前线程。

三、其他高级IO

非阻塞io,纪录锁,系统V流机制,io多路转接(io多路复用),readv和writev函数以及存储映射IO(MMAP),这些统称为高级IO

本文重点讨论IO多路转接

四、非阻塞IO

1.fctl函数

fcntl 一个文件描述符,默认都是阻塞IO

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

传入的cmd不同,后面追加的参数也不同

fcntl函数有5种功能:

  • 复制一个现有的描述符(cmd = F_DUPFD)
  • 获得/设置文件描述符标记(cmd = F_GETFD或F_SETFD)
  • 获得/设置文件状态标记(cmd = F_GETFL或F_SETFL)
  • 获得/设置异步io所有权(cmd = F_GETOWN或F_SETOWN)
  • 获得/设置记录锁(cmd = F_GETLK,F_SETLK或F_SETLKW)

此处使用第三个功能,获取/设置文件状态标记,就可以将一个文件描述符设置为非阻塞

2.实现setNoBlock函数,将文件描述符设置为非阻塞

基于fcntl实现一个SetNoBlock函数

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

使用F_GETFL将当前的文件描述符的属性取出来(这是一个位图).

然后再使用F_SETFL将文件描述符设置回去. 设置回去的同时, 加上一个O_NONBLOCK参数.

3.轮询方式读取标准输入

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>void SetNoBlock(int fd)
{int fl = fcntl(fd,F_GETFL);if(fl <0){perror("fcntl");return;}fcntl(fd,F_SETFL,fl|O_NONBLOCK);
}int main()
{SetNoBlock(0);while(1){char buf[1024] = {0};ssize_t read_size = read(0,buf,sizeof(buf)-1);if(read_size <0){sleep(1);continue;}printf("input:%s\n",buf);return 0;
}

五、IO多路转接之select

1.初始select

系统提供select函数来实现多路复用输入/输出模型

  • select系统调用是用来让我们的程序监视多个fd的状态变化的
  • 程序会停在select这里等待,直到被监视的fd有一个或者多个发生了状态改变

2.select函数原型

#include<sys/select.h>int select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);//nfd 是需要监视的最大文件描述符值+1
//rdset,wrset,exset分别对应需要检测的可读文件描述符的集合,可写文件描述符的集合,以及异常文件描述符的集合
//timeout为结构timeval,用来设置select的等待时间

参数timeout取值:

  • NULL:则表示select()没有timeout,select将一直被阻塞,直到某个文件描述符上发生了事件
  • 0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生
  • 特定的结构值:如果在指定的时间段内没有事件发生,select将超时返回。

fd_set结构

这个结构就是一个整数数组,更严格的说,是一个位图,使用位图中对应的位来表示要监视的文件描述符,有一组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的全部位

关于timeval结构

timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0

strcut timeval
{__time_t tv_sec;   //seconds__suseconds_t tv_usec;   //microseconds
};

函数返回值:

  • 执行成功则返回文件描述词状态已改变的个数
  • 如果返回0代表在描述词状态改变前已经超过timeout时间,没有返回
  • 当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测

错误值可能为:

  • EBADF 文件描述词为无效的或者该文件已关闭
  • EINTR 此调用被信号中断
  • EINVAL 参数n为负值
  • ENOMEN 核心内存不足

常见使用场景:

fs_set readset;
FD_SET(fd,&readset);
select(fd+1,&readset,NULL,NULL,NULL);
if(FD_ISSET(fd,readset)){...}

3.理解select执行过程

理解select模型的关键在于理解ds_set,这里取fd_set长度为1字节,fd_set中的每一个bit可以对应一个文件描述符fd,则1字节长的fd_set最大可以对应8个fd

  1. 执行fd_set set; FD_ZERO(&set); 则set用位表示是0000 0000
  2. 若fd = 5 执行FD_SET(fd,&set);后变为0001 0000
  3. 若再加入fd = 2,fd = 1,则set变成 0001 0011
  4. 执行select(6,&set,0,0,0); 阻塞等待
  5. 若fd = 1,fd = 2 上都发生可读事件,则select返回,此时set变为0000 0011
  6. 注意,没有事件发生的fd = 5被清空

4.select的特点

  • 可监控的文件描述符个数取决与sizeof(fd_set)的值,比如sizeof(fd_set)=512,每bit表示一个文件描述符,则服务器上支持的最大文件描述符是512*8 = 4096
  • 将fd加入select监控集的同时,还要再使用一个数据结构array进行FD_ISSET判断
  • select返回后会把以前加入但是没有发生事件的fd清空,则每次开始select前都要重新从array取得fd逐一加入,扫描array的同时取得fd的最大maxfd,用于select的第一个参数

5.select的缺点

  • 每次调用select,都需要手动设置fd集合,从接口使用角度也非常不便
  • 每次调用select,都需要把fd从用户态拷贝到内核态,这个开销在fd很多时会很大
  • 同时每次调用select都需要在内核遍历传入的所有fd,fd很多的时候开销很大
  • select支持的文件描述符数量太少

6.select使用示例:检测标准输入输出

#include<stdio.h>
#include<unistd.h>
#include<sys/select.h>int main()
{fd_set read_fds;FD_ZERO(&read_fds);FD_SET(0,&read_fds);for(;;){printf("> ");fflush(stdout);int ret = select(1,&read_fds,NULL,NULL,NULL);if(ret <0){perror("select");continue;}if(FD_ISSET(0,&read_fds)){char buf[1024] = {0};read(0,buf,sizeof(buf)-1);printf("input:%s",buf);}else{printf("invalid fd");continue;}FD_ZERO(&read_fds);FD_SET(0,&read_fds);}return 0;
}

7.select使用实例

参照gitee,实现select字典服务器

六、IO多路转接之poll

1.poll函数接口

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

2.参数说明

  • fds是一个poll函数监听的结构列表,每一个元素中包含3部分内容:fd,监听的事件集合,返回的事件集合
  • nfds表示fds数组的长度
  • timeout表示poll函数的超时时间,单位是ms

3.返回结果

返回值小于0,表示出错

返回值等于0,表示poll函数等待超时

返回值大于0,表示poll由于监听的fd就绪而返回

4.poll的优点

不同与select使用三个位图来表示fdset的方式,poll使用一个pollfd指针实现

  • pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式,接口使用比select更方便
  • poll没有max数量限制(但是数量过大后性能也是会下降)

5.poll的缺点

poll中监听的文件fd增多时

  • 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的fd
  • 每次调用poll都需要把大量的pollfd结构从用户态拷贝到内核中
  • 同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的fd数量增加,效率也会线性下降

6.poll使用实例:使用poll监控标准输入

#include <poll.h>
#include <unistd.h>
#include <stdio.h>
int main() {struct pollfd poll_fd;poll_fd.fd = 0;poll_fd.events = POLLIN;for (;;) {int ret = poll(&poll_fd, 1, 1000);if (ret < 0) {perror("poll");continue;}if (ret == 0) {printf("poll timeout\n");continue;}if (poll_fd.revents == POLLIN) {char buf[1024] = {0};read(0, buf, sizeof(buf) - 1);printf("stdin:%s", buf);}}
}

总结

本文主要介绍了select和poll,下一篇文章详解epoll

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

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

相关文章

D365 CRM Power Platform 后端开发概览

博主十年前写的后端技术文章大部分都out-of-date啦&#xff0c;有些东西还能在PP系统中继续沿用&#xff0c;大部分东西都变成old fashion了。 博主后续争取多找些时间&#xff0c;将之前的后端开发文档都翻新一遍&#xff0c;争取与时俱进&#xff0c;让它们还能继续使用下个…

C++const指针的两种用法

const int *p &a; 指向const变量的指针 指向const变量的指针const修饰的变量&#xff0c;只能由指向const变量的指针去指向 p &a1;const的位置&#xff0c;必须在*的左边指向const变量的指针&#xff0c;可以被改变&#xff0c;可以指向别的变量可以指向普通变量&am…

好玩的调度技术-生成式三维技术

好玩的调度技术-生成式三维技术 文章目录 好玩的调度技术-生成式三维技术前言一、效果图&#xff1f;二、技术实现系列文章链接其他文章新篇章 前言 目前休息了&#xff0c;预计休息半年&#xff0c;这半年里只会零星更新一些好玩的技术&#xff0c;感觉好玩系列都快成系列文章…

css之fade 动画效果

1.transition-group transition-group官方文档<TransitionGroup> 是一个内置组件&#xff0c;用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。 2.代码 <div class"senior-panel"><transition-group name"fade">&…

九、基础算法精讲:动态规划二

目录 一、状态机DP1.1 买卖股票的最佳时机 II&#xff08;不限制交易次数&#xff09;1.2 买卖股票的最佳时机含冷冻期1.3 买卖股票的最佳时机 IV1.4 买卖股票的最佳时机含手续费 二、区间DP2.1 最长回文子序列2.2 多边形三角剖分的最低得分2.3 由子序列构造的最长回文串的长度…

详解如何使用VSCode搭建TypeScript环境(适合小白)

搭建Javascript环境 因为TypeScript不能直接在浏览器上运行。它需要编译器来编译并生成JavaScript文件。所以需要首先安装好javascript环境&#xff0c;可以参考文章&#xff1a; 详解如何使用VS code搭建JavaScript环境&#xff08;适合小白&#xff09;_vscode配置javascri…

LeetCode Hot100 437.路径总和III

题目&#xff1a; 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从…

不可错过的设计工具!7款亲测好用的网页设计工具推荐!

网页设计并不容易&#xff0c;易于使用的网页设计工具更难找到。随着网络的快速发展&#xff0c;网站迅速崛起&#xff0c;网页设计也很流行。本文收集了 7 种良心和易于使用的网页设计工具&#xff0c;每一种近年来都受到网页设计师的广泛欢迎&#xff0c;以确保实用和易于使用…

抵御代码重用攻击:指针认证(PAC)和分支目标识别(BTI)

目录 一、代码重用攻击历史 二、小工具(Gadgets):它们是什么?为什么它们很危险? 三、ROP攻击

前端技术探秘-Nodejs的CommonJS规范实现原理 | 京东物流技术团队

了解Node.js Node.js是一个基于ChromeV8引擎的JavaScript运行环境&#xff0c;使用了一个事件驱动、非阻塞式I/O模型&#xff0c;让JavaScript 运行在服务端的开发平台&#xff0c;它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。Node中增添了很…

免费商用字体,进来领取!!!

如果你不知道去哪里找免费可商用字体&#xff0c;那一定要收藏好这几个网站&#xff0c;全部都是免费无版权字体&#xff0c;以后再也不用担心侵权问题了。 1、免费字体网 https://font.sucai999.com/ 一个免费可商用字体搬运工&#xff0c;实时跟新市面上免费商用的字体。网站…

高性能无锁队列 moodycamel::ConcurrentQueue

在做一些服务器的架构设计的时候,你不得不考虑现成模型的设计,将不同的业务划分到不同的线程里,如何来调度这些任务是一个值得有经验的架构师需要思考的工作。 很多开发者一说到线程的任务调度就想到了线程池,给他创建一个线程池,多个线程不断地尝试获取任务的信号,一旦线…

国家万亿资金助力城市生命线城市内涝积水监测系统

自2023年年初以来&#xff0c;我国多个地区遭遇了洪涝、干旱、台风、风雹等灾害的侵袭&#xff0c;部分地区灾情严重&#xff0c;经济损失较大。为应对灾后恢复重建工作的艰巨任务&#xff0c;本次国债将主要投向灾后恢复重建以及提升防灾减灾救灾能力。其中&#xff0c;将全面…

12V 全桥驱动芯片GC9008,0.1A 持续驱动输出电流,可替代MX6208

GC9008 是一款 12V 全桥驱动芯片&#xff0c;为 摄像机、消费类产品提供高性价比的方案。能提供 0.1A 的持续输出电流。 可以工作在 4.5~15V 的电源电压上。 GC9008 具有 PW &#xff08; IN1/IN2 &#xff09;输入接口 , 与行业标准器件兼容. GC9008S 是 SOP8 封装&a…

actual combat 23 —— 通过序列化对字典字段生成字典str字段和对应字典标签值

注解&#xff1a;JsonSerialize(using DictSerializer.class) package com.zyjk.common.core.json;import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JsonMappingException; i…

【JavaEE初阶】 博客系统项目--前端页面设计实现

文章目录 &#x1f332;主要内容&#x1f38d;预期效果&#x1f6a9;博客列表页效果&#x1f6a9;博客详情页&#x1f6a9;博客登录页&#x1f6a9;博客编辑页 &#x1f340;实现博客列表页&#x1f6a9;实现导航栏&#x1f388;页面主体部分 &#x1f384;实现博客详情页&…

使用@autowired 多次插入 修改 会数据出错问题

我这段时间 发现的一个问题 如下 使用 Autowired标注一个 类 Autowired ABC abc ;类如下 Date class ABC { A a&#xff1b; B b&#xff1b; C c&#xff1b; }当第一次插入 abc{ a1&#xff1b; b2&#xff1b; cnull&#xff1b; }成功插入a1&#xff1b;b2&#xff1b;…

【多线程】-- 04 静态代理模式

多线程 3 静态代理 这里以一个现实生活中的例子来解释并实现所谓的静态代理模式&#xff0c;即结婚者雇用婚庆公司来帮助自己完成整个婚礼过程&#xff1a; package com.duo.lambda;interface Marry {void HappyMarry();//人生四大乐事&#xff1a;久旱逢甘霖&#xff1b;他…

文件元数据批量修改:mp3音频和mp4视频的元数据如何批量修改

在数字媒体处理和管理的日常工作中&#xff0c;文件元数据的批量修改是一个常见的需求。元数据&#xff0c;或者称为文件信息&#xff0c;可以包括文件的创建日期、修改日期、文件名、文件大小、标签等。在音乐和视频处理领域&#xff0c;例如对mp3音频和mp4视频文件&#xff0…