IO多路复用原理
(1)IO multiplexing
(2)用在什么地方?多路非阻塞式IO。
(3)select和poll
(4)外部阻塞式,内部非阻塞式自动轮询多路阻塞式IO
IO多路复用原理:
其实就是整个函数对外表现为阻塞式的,也就是我们调用这个函数,如果条件达不到一定
会被阻塞;但是其实内部并不是阻塞的,而是以一种非阻塞的方式工作的,内部能够实现
自动轮询,如果有任何一个IO设备达到条件即可返回到应用层。
用select函数实现IO多路复用:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
原理:通过阻塞监听设备文件是否有数据可操作,如果有数据可读则返回,当然也可以设
置超时时间,然后我们通过read函数去读取/写,所以其实这个就不涉及到read函数是否
是阻塞或者是非阻塞的了。因为select函数返回之后才能读取,所以有数据我们就去读取
,没有我们就不去读。
我们可以设置多路的IO操作,当调用select函数的时候进行阻塞,内部轮询监听是否可以
进行相应的操作,如果那个可以进行操作那么就操作哪个,然后返回到应用层去,结束
select函数的阻塞。
参数详解:
第一个参数:其实就是表示多路IO时,文件描述符最大的值+1,因为我们的fd是从0开始
的。
第二个参数:是一个指向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的全部位
也就是表示在我们打开的所有设备文件中要进行读操作的设备是那些,把他的fd填充进去
,如果所有的都不进行读操作,则写NULL。
第三个参数: 一般是NULL
第四个参数:一般是NULL
第五个参数:表示超时时间(阻塞时间),是一个结构体:如下:
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
有一个秒和一个微秒,是共同配合使用的,xx秒xx微秒
返回值:失败: -1 超时返回 0 成功:> 0
/*************************************************************************/
代码如下:
#include <stdio.h>
//According to POSIX.1-2001
#include <sys/select.h>
//According to earlier standards
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define FILE "/dev/input/mouse0"
int main(void)
{
int fd = -1;
int sele_ret = -1;
fd_set Fd_set;
struct timeval time = {0};
char buf[10] = {0};
//打开设备文件
fd = open(FILE, O_RDONLY);
if (-1 == fd)
{
perror("open error");
exit(-1);
}
//构建多路复用IO
FD_ZERO(&Fd_set); //清除全部fd
FD_SET(0, &Fd_set); //添加标准输入
FD_SET(fd, &Fd_set); //添加鼠标
time.tv_sec = 10; //设置阻塞超时时间为10秒钟
time.tv_usec = 0;
sele_ret = select(fd+1, &Fd_set, NULL, NULL, &time);
if (0 > sele_ret)
{
perror("select error");
exit(-1);
}
else if (0 == sele_ret)
{
printf("无数据输入,等待超时.\n");
}
else
{
if (FD_ISSET(0, &Fd_set)) //监听得到得到的结果若是键盘,则让去读取键盘的数据
{
memset(buf, 0, sizeof(buf));
read(0, buf, sizeof(buf)/2);
printf("读取键盘的内容是: %s.\n", buf);
}
if (FD_ISSET(fd, &Fd_set)) //监听得到得到的结果若是鼠标,则去读取鼠标的数据
{
memset(buf, 0, sizeof(buf));
read(fd, buf, sizeof(buf)/2);
printf("读取鼠标的内容是: %s.\n", buf);
}
}
//关闭鼠标设备文件
close(fd);
return 0;
}
/********************************************************************************/
poll函数实现IO多路复用:
原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数详解:
第一个参数 :struct pollfd {
int fd; //文件描述符
short events; //请求的事件
short revents; //返回的事件
};
其实就是我们多路复用IO的所有文件的fd,注意这里跟select不一样,他是在这个结构体
内进行区分的, events就是表示我们是进行那种操作,是用宏定义的, revents是内核
构建的,返回一个事件,所以我们就是通过 events == revents来确定是不是该fd发生了
可操作。
宏定义如下:
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
第二个参数:就是select的第一个参数
第三个参数:阻塞超时时间,以毫秒为单位
返回值:跟select是一样的,失败-1 超时0 >0成功
代码如下:
/*****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FILE "/dev/input/mouse0"
int main(void)
{
int fd = -1;
int poll_ret = 0;
struct pollfd poll_fd[2] = {0};
char buf[100] = {0};
//打开设备文件
fd = open(FILE, O_RDONLY);
if (-1 == fd)
{
perror("open error");
exit(-1);
}
//构建多路复用IO
poll_fd[0].fd = 0; //键盘
poll_fd[0].events = POLLIN; //定义请求的事件为读数据
poll_fd[1].fd = fd; //鼠标
poll_fd[1].events = POLLIN; //定义请求的事件为读数据
int time = 10000; //定义超时时间为10秒钟
poll_ret = poll(poll_fd, fd+1, time);
if (0 > poll_ret)
{
perror("poll error");
exit(-1);
}
else if (0 == poll_ret)
{
printf("阻塞超时.\n");
}
else
{
if (poll_fd[0].revents == poll_fd[0].events) //监听得到得到的结果若是键盘,则让去读取键盘的数据
{
memset(buf, 0, sizeof(buf));
read(0, buf, sizeof(buf)/2);
printf("读取键盘的内容是: %s.\n", buf);
}
if (poll_fd[1].revents == poll_fd[1].events) //监听得到得到的结果若是鼠标,则去读取鼠标的数据
{
memset(buf, 0, sizeof(buf));
read(fd, buf, sizeof(buf)/2);
printf("读取鼠标的内容是: %s.\n", buf);
}
}
//关闭文件
close(fd);
return 0;
}
IO多路复用原理的更多相关文章
- IO多路复用原理&场景
目录 IO多路复用的历史 阻塞 IO 非阻塞 IO IO 多路复用 select poll epoll IO多路复用高效的原因 IO多路复用解决的什么问题 epoll比selector性能一定更好吗 ...
- 理论铺垫:阻塞IO、非阻塞IO、IO多路复用/事件驱动IO(单线程高并发原理)、异步IO
完全来自:http://www.cnblogs.com/alex3714/articles/5876749.html 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同 ...
- socket_server源码剖析、python作用域、IO多路复用
本节内容: 课前准备知识: 函数嵌套函数的使用方法: 我们在使用函数嵌套函数的时候,是学习装饰器的时候,出现过,由一个函数返回值是一个函数体情况. 我们在使用函数嵌套函数的时候,最好也这么写. def ...
- python之IO多路复用
在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...
- IO多路复用的几种实现机制的分析
http://blog.csdn.net/zhang_shuai_2011/article/details/7675797 select,poll,epoll都是IO多路复用的机制.所谓I/O多路复用 ...
- 转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select/Poll/Epoll使用】
下面这篇,原理理解了, 再结合 这一周来的心得体会,整个框架就差不多了... http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架, ...
- I/O模型系列之五:IO多路复用 select、poll、epoll
IO多路复用之select.poll.epoll IO多路复用:通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. 应用:适用于针 ...
- IO多路复用和local概念
一.local 在多个线程之间使用threading.local对象,可以实现多个线程之间的数据隔离 import time import random from threading import T ...
- 异步、非阻塞和IO多路复用总结
Nginx是并发处理框架的代表者,很多后台业务都会放在Nginx容器中运行,以实现高吞吐,而Nginx能够支持高并发也是由于使用了异步非阻塞处理模型,本文将用通俗的话讲解异步.同步.阻塞.非阻塞的区别 ...
随机推荐
- java之扫描包里面的class文件
一.class作为,编译过后的产物,在很多时候,我们需要通过反射去执行class的具体方法.但是扫描class就是一个很大的问题了. 二.所以我这里写了一个简单的class文件扫描方式. 三.主要是利 ...
- 6.5笔记-DQL高级查询
一.高级查询 Exists Drop table if exists result; 子查询有返回结果: EXISTS子查询结果为TRUE 子查询无返回结果: EXISTS子查询结果为FALSE, 外 ...
- java8时间使用小结
//LocalDate代表一个IOS格式(yyyy-MM-dd)的日期 获取当前的日期: LocalDate localDate = LocalDate.now();//LocalDate: 表示没有 ...
- 线程的等待方法:join
其实多线程最复杂的地方在于不同线程间的同步问题,这其中会涉及到先后执行问题.共享变量问题等.这篇文章我们主要来开个头,看一下join方法. using System; using System.Thr ...
- win10 svn commit无响应
只是发现其中的一个原因,发现.cs代码文件图标变红了,默认是用Code Writer打开,和SVN可能是冲突了,解决方式是用Code Writer打开一下.cs文件就可以了,原因可能是不打开一次Cod ...
- 学习了django对于sqlite3进行了了解,谈谈看法
学习了django对于sqlite3进行了了解,谈谈看法 由于django默认使用的是sqlite3,写了几个建表语句, 然后数据做下迁移,其实就是建表语句的执行. 一直对sqlite3没有一个直观的 ...
- 好记性不如烂笔头-linux学习笔记4apache相关知识
apache 启动有2种模式 1是prefork模式,每个进程对应一个线程,如果是比较稳定的平台,那么prefork模式是worker模式 比较好,效率高,但是吃的内存比较大. 2 如果是高负载高并发 ...
- OpenCL 前缀和
▶ 向量前缀和 ● 最简单的版本,代码 #include <stdio.h> #include <stdlib.h> #include <cl.h> const c ...
- lombok 的使用
参考:https://blog.csdn.net/motui/article/details/79012846
- 值得推荐的开源C/C++框架和库
值得学习的C语言开源项目 - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工 ...