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
- 执行fd_set set; FD_ZERO(&set); 则set用位表示是0000 0000
- 若fd = 5 执行FD_SET(fd,&set);后变为0001 0000
- 若再加入fd = 2,fd = 1,则set变成 0001 0011
- 执行select(6,&set,0,0,0); 阻塞等待
- 若fd = 1,fd = 2 上都发生可读事件,则select返回,此时set变为0000 0011
- 注意,没有事件发生的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
相关文章:
Linux多路转接select,poll
文章目录 目录 文章目录 一、五种IO模型 1.阻塞IO: 2.非阻塞IO 3.信号驱动IO 4.IO多路转接 5.异步IO 二、高级IO的一些重要概念 1.同步通信和异步通信 2.阻塞和非阻塞 三、其他高级IO 四、非阻塞IO 1.fctl函数 2.实现setNoBlock函数,将文件描述符设置…...
如何轻松将 4K 转换为 1080p 高清视频
由于某些原因,你可能有一些 4K 视频,与1080p、1080i、720p、720i等高清视频相比,4K 视频具有更高的分辨率,可以给您带来更多的视觉和听觉享受。但是,播放4k 视频是不太容易的,因为超高清电视没有高清电视那…...
责任链模式 (Chain of Responsibility Pattern)
定义 责任链模式是一种行为型设计模式,用于在对象间建立一条处理请求的链。它允许多个对象有机会处理请求,从而减少请求的发送者和接收者之间的耦合。在责任链模式中,每个接收者包含对另一个接收者的引用,形成一条链。如果一个对…...
企业营销管理能够实现自动化吗?怎么做?
当今企业面临着越来越多的营销难题:如何有效培育潜在客户、如何提高营销活动的效果、如何优化营销资源的分配......企业的营销管理怎么做?或许CRM系统营销自动化会起到作用。 客户细分: 企业可以通过CRM的客户细分功能,根据客户…...
【数据结构】什么是栈?
🦄个人主页:修修修也 🎏所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 📌栈的定义 📌元素进栈出栈的顺序 📌栈的抽象数据类型 📌栈的顺序存储结构 📌栈的链式存储结构 链栈的进…...
基于C#实现鸡尾酒排序(双向冒泡排序)
通俗易懂点的话,就叫“双向冒泡排序”。 冒泡是一个单向的从小到大或者从大到小的交换排序,而鸡尾酒排序是双向的,从一端进行从小到大排序,从另一端进行从大到小排序。 从图中可以看到,第一次正向比较,我们…...
CentOS添加开机启动
1.编写项目启动脚本(run.sh) #!/bin/bash-切换到程序所在路径 cd /home/cavs_install/app/cavs-admin/target/ # 等待其他组件启动完毕后再启动本项目(如果不需要等待,本步骤可省略) sleep 300 # 实际启动命令 nohup …...
SpringCloudAlibaba之Nacos的持久化和高可用——详细讲解
目录 一、Nacos持久化 1.持久化说明 2.安装mysql数据库5.6.5以上版本(略) 3.修改配置文件 二、nacos高可用 1.集群说明 2.nacos集群架构图 2.集群搭建注意事项 3.集群规划 4.搭建nacos集群 5.安装Nginx 6.配置nginx conf配置文件 7.启动nginx进行测试即可 一、Nacos持久…...
vue3安装eslint和prettier,最简单的步骤
第1步: 安装eslint yarn add eslint -D 第2步: 在根文件夹中,创建.eslintrc.js文件 第3步: 在package.json文件中新增命令 "lint": "eslint --fix --ext .ts,.tsx,.vue src --quiet","prettier"…...
Day32| Leetcode 122. 买卖股票的最佳时机 II Leetcode 55. 跳跃游戏 Leetcode 45. 跳跃游戏 II
Leetcode 122. 买卖股票的最佳时机 II 题目链接 122 买卖股票的最佳时机 II 本题目设计的还是比较巧妙的,把最终的利润分为每天的利润就解决了(贪心),每天的利润就是前一天买进,后一天卖出,转化到代码上就…...
95.STL-遍历算法 for_each
算法概述: 算法主要是由头文件 <algorithm> <functional> <numeric> 组成。 <algorithm> 是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等 <numeric> 体积很小,只包括几个在序列上面…...
Python基础语法之学习type()函数
Python基础语法之学习type函数 一、代码二、效果 查看数据类型或者说查看变量存储的数据类型 一、代码 print(type("文本")) print(type(666)) print(type(3.14))二、效果 梦想是生活的指南针,坚持追逐梦想,终将抵达成功的彼岸。不要害怕失败…...
filebeat报错dropping too large message of size
filebeat报错: dropping too large message of size 1714620. 原因: kafka对每一条消息的大小进行了限制。 解决 kafka端 修改config/server.properties,添加以下配置 max_message_bytes10000000 replica.fetch.max.bytes10000000修改…...
【C++】类型转换 ④ ( 子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast )
文章目录 一、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast1、构造父类和子类2、子类 和 父类 之间的类型转换 - 隐式类型转换3、子类 和 父类 之间的类型转换 - 静态类型转换 static_cast4、子类 和 父类 之间的类型转换 - 重新解释类型转换 reinterpret_cast5、…...
在CentOS 7.9上搭建高性能的FastDFS+Nginx文件服务器集群并实现外部远程访问
文章目录 引言第一部分:FastDFS介绍与安装1.1 FastDFS简介1.2 FastDFS安装1.2.1 安装Tracker Server1.2.2 安装Storage Server 1.3 FastDFS配置1.3.1 配置Tracker Server1.3.2 配置Storage Server1.3.3 启动FastDFS服务 第二部分:Nginx配置2.1 Nginx安装…...
YOLOv8独家原创改进: AKConv(可改变核卷积),即插即用的卷积,效果秒杀DSConv | 2023年11月最新发表
💡💡💡本文全网首发独家改进:可改变核卷积(AKConv),赋予卷积核任意数量的参数和任意采样形状,为网络开销和性能之间的权衡提供更丰富的选择,解决具有固定样本形状和正方形的卷积核不能很好地适应不断变化的目标的问题点,效果秒殺DSConv 1)AKConv替代标准卷积进行…...
Docker pause/unpause命令
docker pause :暂停容器中所有的进程。 docker unpause :恢复容器中所有的进程。 语法 docker pause CONTAINER [CONTAINER...]docker unpause CONTAINER [CONTAINER...]实例 暂停数据库容器db01提供服务。 docker pause db01恢复数据库容器db01提供…...
PostgreSQL create or replace view和重建视图 有什么区别?
一、 replace vs 重建 遇到开发提了个问题,create or replace view和重建视图(dropcreate)有什么区别,查询资料整理了一下。 1. create or replace 当存在同名视图时,尝试将其替换新视图语句必须与现有视图查询具有相…...
Selenium 连接到现有的 Firefox 示例
当前环境: python 3.7 selenium 3.14.1 urllib3 1.26.8 Frefox 115.1.0esr(32位) geckodriver.exe 0.33.0 1 下载 Firefox 浏览器,根据自己的需要选择。 下载 Firefox 浏览器,这里有简体中文及其他 90 多种语言版本…...
小程序如何进行版本回退
当商家决定回退小程序版本时,可能是因为新版本出现了一些问题或者不符合预期,需要恢复到之前的稳定版本。下面具体介绍怎么回退小程序的版本。 在小程序管理员后台->版本设置处,点击版本回退。确认后,小程序会回退到上一次的版…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
2025-05-08-deepseek本地化部署
title: 2025-05-08-deepseek 本地化部署 tags: 深度学习 程序开发 2025-05-08-deepseek 本地化部署 参考博客 本地部署 DeepSeek:小白也能轻松搞定! 如何给本地部署的 DeepSeek 投喂数据,让他更懂你 [实验目的]:理解系统架构与原…...
