详解I/O多路转接之select
什么是多路转接IO
对大量的描述符进行I/O事件监控—可以告诉进程现在有哪些描述符就绪了,然后进行就可以只针对就绪了的描述符进行响应操作,避免对没有就绪的I/O操作所导致的效率降低和流程阻塞。
- IO事件:可读事件/可写事件/异常事件
I/O多路转接模型之select
select介绍
系统提供select函数来实现多路复用输入/输出模型.
- select系统调用是用来让我们的程序监视多个文件描述符的状态变化的;
- 程序会停在select这里等待,直到被监视的文件描述符有一个或多个发生了状态改变
操作流程:
1.程序员定义某个事件的描述符集合(可读事件的描述符集合/可写事件的描述符集合/异常事件的描述符集合),初始化清空集合
对哪个描述符关心什么事件,就把这个描述符添加到相应时间的描述符集合中
2.发起监控调用,将集合拷贝到内核中进行监控,监控的原理原理是轮询遍历判断
可读事件的就绪:接收缓冲区中数据的大小低于水位标记(量化标准–通常默认为1个字节)
可写事件的就绪:发送缓冲区中剩余空间的大小大于低水位标记(量化标准—通常默认为1个字节)
异常事件的就绪:描述符是否产生了某个异常
3.监控的调用返回,表示监控出错/有描述符就绪/监控等待超时了
并且调用返回的时候,将事件监控的描述符集合中的未就绪描述符从集合中移除了----(集合中仅仅保留就绪的描述符)
因为返回的时候修改了集合,因此下次监控的时候,就需要重新向集合中添加描述符
4.程序员轮询判断那个描述符仍然在哪个集合中,就确定这个描述符是否就绪了某个事件,然后进行对应事件的操作即可
select并不会直接返回给用户就绪的描述符,而是返回了就绪的描述符集合,因此需要程序员进行判断
代码操作:
1.定义集合—struct fd_set
,成员只有一个数组(当做二进制位图使用)添加描述符就是将描述符对应的比特位置1
因此select能够监控的描述符数量,取决于二进制比特位多少,而比特位多少取决于宏 ,FD_SETSIZE,默认等于1024
void FD_ZERO(fd_set* set);//初始化清空集合
void FD_SET(int fd,fd_set* set);//将fd描述符添加到set集合中
- select开始调用监控
int select(int nfds,fd_set* readfds, fd_set* writefds, fd_set *exceptfds, struct timeval* timeout);
- nfds:当前监控的集合中最大的描述符+1,减少遍历次数
- readfds/writefds/exceptfds:可读/可写/异常三种事件的描述符集合
- timeout:
struct timeval{tv_sec;tv_usec};
时间结构体,通过这个时间决定select阻塞/非阻塞/限制超时的阻塞
若timeout为NULL,则表示阻塞监控,直到描述符就绪/出错才会返回
若timeout中的成员数据为0,则表示阻塞,监控的时候若没有描述符就绪,则立即超时返回
若timeout中成员数据不为0,则在指定的时间内,没有就绪则超时返回
返回值:>0表示就绪的描述符个数
==0表示没有描述符就绪,超时返回
<0表示是监控出错
3.调用返回,返回给程序员,就绪的描述符集合,程序员遍历判断哪个描述符还在哪个集合中,就是就绪了那个事件
int FD_ISSET(int fd,fd_set *set);
//判断fd描述符是否在集合中
注意:因为select返回时会修改集合,因此每次监控的时候都要重新添加描述符
4.若对描述符不想进行监控了,则从集合中移除描述符
void FD_CLR(int fd,fd_set* set);//从描述符中删除描述符fd
select就绪条件
读就绪
- socket内核中, 接收缓冲区中的字节数, 大于等于低水位标记SO_RCVLOWAT. 此时可以无阻塞的读该文件 描述符, 并且返回值大于0;
- socket TCP通信中, 对端关闭连接, 此时对该socket读, 则返回0;
- 监听的socket上有新的连接请求;
- socket上有未处理的错误;
写就绪
- socket内核中, 发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小), 大于等于低水位标记 SO_SNDLOWAT, 此时可以无阻塞的写, 并且返回值大于0;
- socket的写操作被关闭(close或者shutdown). 对一个写操作被关闭的socket进行写操作, 会触发SIGPIPE 信号;
- socket使用非阻塞connect连接成功或失败之后;
- socket上有未读取的错误;
异常就绪
- socket上收到带外数据. 关于带外数据, 和TCP紧急模式相关(TCP协议头中, 有一个紧急指针的字段).
select优缺点分析
缺点
- select对描述符进行监控有最大数量上限,上限取决于宏-FD_SETSIZE,默认大小是1024
- 在内核中进行监控,是通过轮询遍历判断实现的,性能会随着描述符的增多而下降
- 只能返回就绪的集合,需要进程进行轮询遍历判断才能得知那个描述符就绪了哪个事件
- 每次监控都需要重新添加描述符到集合中,每次监控都需要将集合重新拷贝到内核中
优点:
遵循POSIX标准,跨平台移植性好
使用select简单检测标准输入
#include<sys/select.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/time.h>
#include<unistd.h>
#include<cstdio>
#include<time.h>
int main(int argc,char* argv[]){fd_set rfds;FD_ZERO(&rfds);//初始化描述符集合FD_SET(0,&rfds);//将描述符fd添加到描述符集合while(1){printf(">");fflush(stdout);int ret=select(1,&rfds,NULL,NULL,NULL);//监控if(ret<0){//监控错误perror("select error");continue;}if(FD_ISSET(0,&rfds)){//描述符已就绪char buf[1024];read(0,buf,sizeof(buf)-1);printf("buf-->%s\n",buf);}else{//描述符未就绪perror("error! invaild fd\n");continue;}FD_ZERO(&rfds);//将描述符置为0FD_SET(0,&rfds);//将标准输入描述符添加到集合中}return 0;
}
运行结果:
详解I/O多路转接之select相关推荐
- Linux下I/O多路转接之select --fd_set
fd_set 你终于还是来了,能看到这个标题进来的,我想,你一定是和我遇到了一样的问题,一样的疑惑,接下来几个小时,我一定竭尽全力,写出我想说的,希望也正是你所需要的: 关于Linux下I/O多路转接 ...
- I/O多路转接之select
I/O多路转接之select 文章目录 I/O多路转接之select 一.五种IO模型 二.I/O多路转接之select原理 一.五种IO模型 阻塞IO: 在内核将数据准备好之前, 系统调用会一直等待 ...
- I/O多路转接之 select
系统提供select函数来实现多路复用输入/输出模型. 作用:select系统调用是用来让我们的程序监视多个文件句柄的状态变化的.程序会停在select这里等待,直到被监视的文件句柄有一个或多个发生了 ...
- Linux:I/O多路转接之select(有图有代码有真相!!!)
一.select引入 一次 I/O 分为两个部分:1)等待数据就绪 2)进行数据转移 1.select 原理: select的原理就是减少等待数据就绪的比重,巧妙的利用等待队列机制让用户进程 ...
- 高级IO(多路转接之select、poll、epoll->核反应堆模式)
꧁ 大家好,我是 兔7 ,一位努力学习C++的博主~ ꧂ ☙ 如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步❧
- select poll epoll 高效IO 多路转接
目录 五种常见IO模型 高效IO的概念 阻塞 vs 非阻塞 非阻塞IO fcntl函数 I/O多路转接之select 初识select select函数原型 select操作接口 tcp_server ...
- Python中的select、epoll详解
Python中的select.epoll详解 文章目录 Python中的select.epoll详解 一.select 1.相关概念 2.select的特性 1.那么单进程是如何实现多并发的呢??? ...
- java爬取网页内容 简单例子(2)——附jsoup的select用法详解
[背景] 在上一篇博文 java爬取网页内容 简单例子(1)--使用正则表达式 里面,介绍了如何使用正则表达式去解析网页的内容,虽然该正则表达式比较通用,但繁琐,代码量多,现实中想要想出一条简单的正则 ...
- IO多路转接 ——— select、poll、epoll
文章目录 I/O多路转接之select select初识 select函数 socket就绪条件 select基本工作流程 select服务器 select的优点 select的缺点 select的适 ...
最新文章
- ubuntu14.04初体会
- 图解 Java 垃圾回收机制,写得非常好!
- python的head函数_python – 是否有一个pandas函数来显示第一个/最后一个n列,如.head().tail()?...
- php链接页面时加..,怎么给一个PHP密码访问页面加超链接
- Python 循环列表删除元素的注意事项
- Android 进阶 教你打造 Android 中的 IOC 框架 【ViewInject】 (上)
- 【Python3爬虫】破解时光网登录加密参数并实现模拟登录
- php读取pdf文件乱码,使用php读取pdf文件
- VXLAN简明学习笔记(原创)
- VMware Workstation 14 Pro 安装 Windows Server 2003(完)
- Java面向对象编程 实验报告
- 电子商务概论(农)之章节课后题
- 如何解决DMS的个人数据隐私问题?ToF技术路线在路上
- 标学历年真题2016年版 真考题库1 电子表格
- 串口服务器采集需要通讯协议么,C2000-A2-SDX6000-CX1
- 跟小静读CLR via C#(06)- 构造器
- 微信公共平台配置域名提示,协议头非法
- 【台大郭彦甫】Matlab入门教程超详细学习笔记四:数据类型与文件读写(附PPT链接)
- Docker | 基于docker安装Redis
- js html css淘宝足迹日历效果,JavaScript实现简单日历效果