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,一经查实,立即删除!

相关文章

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

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

详解如何使用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;以确保实用和易于使用…

前端技术探秘-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;实时跟新市面上免费商用的字体。网站…

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

自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…

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

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

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

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

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

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

linux下的工具---gdb

一、gdb简介 GDB,是The GNU Project Debugger 的缩写&#xff0c;是 Linux 下功能全面的调试工具。 GDB支持断点、单步执行、打印变量、观察变量、查看寄存器、查看堆栈等调试手段。 程序的发布方式有两种&#xff0c;debug模式和release模式 Linux gcc/g出来的二进制程序&am…

自驾游汽车托运是交智商税吗?

自驾游汽车托运是交智商税吗? 亲爱的小伙伴们 你们有没有遇到过这样的困扰&#xff1a; 自驾游时&#xff0c;车辆的运输问题让你头疼不已? 是选择自己驾驶还是托运呢? 今天&#xff0c;我就来给大家种草一下汽车托运的好处&#xff0c; 让你的自驾游之旅更加轻松愉快! 1️.…

安防视频监控/磁盘阵列/集中云存储平台EasyCVR设备录像保活不生效原因是什么?该如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

【Linux】安卓端JuiceSSH结合内网穿透实现远程连接服务器

目录 前言1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 前言 处于内网的虚拟机如何被外网访问呢&#xff1f;如何手机就能访问虚拟机呢&#xff1f; 本文介绍 cpolarJuiceSSH 实现手机端远程连接Linux虚拟…

elk日志分析系统:

elk日志分析系统: elk是一套完整的日志集中处理方案&#xff0c;由三个开源的软件简称组成&#xff1b; E:Easticsearch 简称ES是一个开源的&#xff0c;分布式的存储检索引擎&#xff0c;&#xff08;索引型的非关系数据库&#xff09;存储日志 由java代码开发的&#xff0…

CSC公派博士后|管理学老师赴韩国首尔大学达成目标

J老师自身背景正好卡在CSC公派博士后申报条件的边缘&#xff0c;为增大通过概率&#xff0c;其提出优选亚洲范围内的世界知名高校、专业相符、2年博士后职位的要求。最终我们用韩国首尔大学的邀请函助其顺利获批CSC&#xff0c;实现了所有既定目标。 J老师背景&#xff1a; 申…

【Tiny_CD】Tiny_CD变化检测网络详解(含python代码)

题目:TinyCD: A (Not So) Deep Learning Model For Change Detection 论文:paper 代码:code 目录 🍟 🍟1.摘要 🍗🍗 2.贡献 🍖🍖 3.网络结构

前端必学——实现电商图片放大镜效果(附代码)

放大镜可以说是前端人必须学会的程序之一,今天的案例为大家展示一下怎么实现放大镜的效果&#xff01; 效果图展示 整个效果就是当鼠标放到展示图上的时候&#xff0c;会出现一个遮罩层以及弹出来一个框展示一个详情图&#xff0c;并且鼠标移动的时候详情图跟着移动&#xff0…