一.IO处理模型
1.阻塞IO模型
如果所调用的IO函数没有完成相应的IO功能,会使进程挂起,直到等待的相关数据到达才会返回。比如对管道设备,终端设备,网络设备等的操作。
2.非阻塞IO模型
当请求不能满足的时候,不会让进程睡眠,而是直接睡眠。比如我们常见的open,write,read等函数。
3.多路转接模型
如果请求得不到满足,但是又不是真的IO阻塞,而是其中的一个函数等待,在此期间函数还可以进行其他操作,比如select以及poll函数就是这种类型。
4.信号驱动IO模型
进程要定义一个信号处理程序,系统可以自动捕获特定信号的的到来,从而启动IO操作,由内核通知用户何时可以启动一个IO操作。
5.异步IO模型
先让内核其哦对嗯IO操作,完成以后再通知进程IO操作结束。
二.关于多路转接模型
select和poll函数,他们可以设定程序中所关心的文件描述符,希望等待的时间等。从函数返回的时候,内核会通知用户准备好的文件描述符的数量,已经准备好的条件或者事件等。通过select和poll的返回结果,对应检测到某个文件描述符的注册事件或者是超时,或者是调用出错。
三.select函数说明
1.所需头文件
<sys/types.h>
<sys/time.h>
<unistd.h>
2.函数原型
int select(int numfds,fd_set *readfds,fd_set *writefds,fd_set *exeptfds,struct timeval *timeout);
3.参数说明
(1)numfds:为需要监视的文件描述符的最大值加1
(2)readfds:由select函数监视的读文件描述符集合
(3)writefds:由select函数监视的写文件描述符集合
(4)exeptfds:由select函数监视的异常处理文件描述符集合
(5)timeout:
----》NULL:永远等待
----》具体值:具体的超时值
----》0:从不等待,测试所有指定的文件描述符立即返回
4.返回值
成功:准备好的文件描述符
失败:-1
超时:0
5.select涉及到的文件描述符处理宏定义函数
(1)FD_ZERO(fd_set *set):清除一个文件描述符集合
(2)FD_SET(int fd,fd_set *set):将一个文件描述符加入到set集合
(3)FD_CLR(int fd,fd_set *set):将一个文件描述符从set集合删除
(4)FD_ISSET(int fd,fd_set *set):测试fd是否属于set。可以用于调用select以后检测集合中的哪个文件描述符是否有变化
(5)FD_SETSIZE表示fd_set结构能够容纳的文件描述符的最大数目
6.注意事项
(1)使用select函数之前一般要用FD_ZERO和FD_SET初始化文件描述符集合
(2)在重复调用select函数的时候,先把一次初始化好的文件描述符集合备份下来,每次读取他即可
(3)在select返回以后,可循环使用FD_ISSET来测试描述符集合
(4)在执行完对相关文件描述符的操作以后,用FD_CLR清除该文件描述符
四.poll函数说明
1.头文件
<sys/types.h>
<poll.h>
2.函数原型
int poll(struct pollfd *fds,int numfds,int timeout);
3.参数说明
(1)fds:用于描述需要对哪些文件的哪种类型的操作进行监控
(2)numfds:需要监听的文件个数,即第一个参数所指向的数组中的元素数目
(3)timeout:阻塞的超时时间,精确到毫秒级别,如果小于0,表示无限等待
4.返回值:
成功:大于0,表示事件发生的pollfd结构的个数
失败:-1
超时:0
五.使用实例
1.select的弊端
(1)内核必须检查多余的文件描述符
(2)每次调用select以后都要重置被监听的文件描述符集合
(3)可监听的文件描述符个数受限制
2.用mknod命令创建两个管道in1,in2,然后在两个虚拟终端分别运行cat>in1和cat>in2,同时在第三个终端运行主程序。
3.如果三个文件一直处于无输入状态,则主程序一直处于阻塞状态,为了防止无限期等待,在主程序中设置超时值。
4.实际代码
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <poll.h>
#define MAX_BUFSIZE 1024
#define IN_FILES 3
#define TIME_OUT 60000
#define MAX(a,b) ((a > b) ? (a): (b))
int main(void)
{
struct pollfd fds[IN_FILES];
char buf[MAX_BUFSIZE];
int i,res,real_read,maxfd;
/*open two source files with some permission*/
fds[0].fd = 0;
if((fds[1].fd = open("in1",O_RDONLY|O_NONBLOCK)) < 0)
{
printf("open in1 error!\n");
return 1;
}
if((fds[2].fd = open("in2",O_RDONLY|O_NONBLOCK)) < 0)
{
printf("open in2 error!\n");
return 1;
}
/*achieve the bigger one from two filedescriptions*/
for(i = 0; i < IN_FILES;i++)
{
fds[i].events = POLLIN;
}
while(fds[0].events || fds[1].events || fds[2].events)
{
if(poll(fds,IN_FILES,0) < 0)
{
printf("Poll error or time out\n");
return 1;
}
for(i = 0;i < IN_FILES;i++)
{
if(fds[i].events)
{
memset(buf,0,MAX_BUFSIZE);
real_read = read(fds[i].fd,buf,MAX_BUFSIZE);
if(real_read < 0)
{
if(errno != EAGAIN)
{
return 1;
}
}
else if(!real_read)
{
close(fds[i].fd);
fds[i].events = 0;
}
else{
if(i == 0)
{
if((buf[0] == 'q') || (buf[0] == 'Q'))
{
return 1;
}
}
else{
buf[real_read] = '\0';
printf("%s",buf);
}
}
}
}
}
exit(0);
}
1.阻塞IO模型
如果所调用的IO函数没有完成相应的IO功能,会使进程挂起,直到等待的相关数据到达才会返回。比如对管道设备,终端设备,网络设备等的操作。
2.非阻塞IO模型
当请求不能满足的时候,不会让进程睡眠,而是直接睡眠。比如我们常见的open,write,read等函数。
3.多路转接模型
如果请求得不到满足,但是又不是真的IO阻塞,而是其中的一个函数等待,在此期间函数还可以进行其他操作,比如select以及poll函数就是这种类型。
4.信号驱动IO模型
进程要定义一个信号处理程序,系统可以自动捕获特定信号的的到来,从而启动IO操作,由内核通知用户何时可以启动一个IO操作。
5.异步IO模型
先让内核其哦对嗯IO操作,完成以后再通知进程IO操作结束。
二.关于多路转接模型
select和poll函数,他们可以设定程序中所关心的文件描述符,希望等待的时间等。从函数返回的时候,内核会通知用户准备好的文件描述符的数量,已经准备好的条件或者事件等。通过select和poll的返回结果,对应检测到某个文件描述符的注册事件或者是超时,或者是调用出错。
三.select函数说明
1.所需头文件
<sys/types.h>
<sys/time.h>
<unistd.h>
2.函数原型
int select(int numfds,fd_set *readfds,fd_set *writefds,fd_set *exeptfds,struct timeval *timeout);
3.参数说明
(1)numfds:为需要监视的文件描述符的最大值加1
(2)readfds:由select函数监视的读文件描述符集合
(3)writefds:由select函数监视的写文件描述符集合
(4)exeptfds:由select函数监视的异常处理文件描述符集合
(5)timeout:
----》NULL:永远等待
----》具体值:具体的超时值
----》0:从不等待,测试所有指定的文件描述符立即返回
4.返回值
成功:准备好的文件描述符
失败:-1
超时:0
5.select涉及到的文件描述符处理宏定义函数
(1)FD_ZERO(fd_set *set):清除一个文件描述符集合
(2)FD_SET(int fd,fd_set *set):将一个文件描述符加入到set集合
(3)FD_CLR(int fd,fd_set *set):将一个文件描述符从set集合删除
(4)FD_ISSET(int fd,fd_set *set):测试fd是否属于set。可以用于调用select以后检测集合中的哪个文件描述符是否有变化
(5)FD_SETSIZE表示fd_set结构能够容纳的文件描述符的最大数目
6.注意事项
(1)使用select函数之前一般要用FD_ZERO和FD_SET初始化文件描述符集合
(2)在重复调用select函数的时候,先把一次初始化好的文件描述符集合备份下来,每次读取他即可
(3)在select返回以后,可循环使用FD_ISSET来测试描述符集合
(4)在执行完对相关文件描述符的操作以后,用FD_CLR清除该文件描述符
四.poll函数说明
1.头文件
<sys/types.h>
<poll.h>
2.函数原型
int poll(struct pollfd *fds,int numfds,int timeout);
3.参数说明
(1)fds:用于描述需要对哪些文件的哪种类型的操作进行监控
(2)numfds:需要监听的文件个数,即第一个参数所指向的数组中的元素数目
(3)timeout:阻塞的超时时间,精确到毫秒级别,如果小于0,表示无限等待
4.返回值:
成功:大于0,表示事件发生的pollfd结构的个数
失败:-1
超时:0
五.使用实例
1.select的弊端
(1)内核必须检查多余的文件描述符
(2)每次调用select以后都要重置被监听的文件描述符集合
(3)可监听的文件描述符个数受限制
2.用mknod命令创建两个管道in1,in2,然后在两个虚拟终端分别运行cat>in1和cat>in2,同时在第三个终端运行主程序。
3.如果三个文件一直处于无输入状态,则主程序一直处于阻塞状态,为了防止无限期等待,在主程序中设置超时值。
4.实际代码
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <poll.h>
#define MAX_BUFSIZE 1024
#define IN_FILES 3
#define TIME_OUT 60000
#define MAX(a,b) ((a > b) ? (a): (b))
int main(void)
{
struct pollfd fds[IN_FILES];
char buf[MAX_BUFSIZE];
int i,res,real_read,maxfd;
/*open two source files with some permission*/
fds[0].fd = 0;
if((fds[1].fd = open("in1",O_RDONLY|O_NONBLOCK)) < 0)
{
printf("open in1 error!\n");
return 1;
}
if((fds[2].fd = open("in2",O_RDONLY|O_NONBLOCK)) < 0)
{
printf("open in2 error!\n");
return 1;
}
/*achieve the bigger one from two filedescriptions*/
for(i = 0; i < IN_FILES;i++)
{
fds[i].events = POLLIN;
}
while(fds[0].events || fds[1].events || fds[2].events)
{
if(poll(fds,IN_FILES,0) < 0)
{
printf("Poll error or time out\n");
return 1;
}
for(i = 0;i < IN_FILES;i++)
{
if(fds[i].events)
{
memset(buf,0,MAX_BUFSIZE);
real_read = read(fds[i].fd,buf,MAX_BUFSIZE);
if(real_read < 0)
{
if(errno != EAGAIN)
{
return 1;
}
}
else if(!real_read)
{
close(fds[i].fd);
fds[i].events = 0;
}
else{
if(i == 0)
{
if((buf[0] == 'q') || (buf[0] == 'Q'))
{
return 1;
}
}
else{
buf[real_read] = '\0';
printf("%s",buf);
}
}
}
}
}
exit(0);
}