1.
IO多路复用含义:
IO: 输入输出操作;
多路复用:若请求的
IO操作阻塞,且它不是真正阻塞IO,而是让其中的一个函数等待,在这期间,IO 还能进行其他的操作。该函数有select() 和 poll()两个函数。
2.
Selete()和poll()函数:
设置程序中每一个所关心的文件描述符的条件、希望等待的时间等,
selete()和poll() 函数返回时内核会通知用户已经准备好的文件描述符的数量、已准备好的条件等。
通过使用
selete()和poll() 函数的返回结果,就可调用相应的IO处理函数;
2.1 Select()函数介绍:
#include
#include
#include
int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exeptfds, struct timeval *timeout);
参数说明:
函数参数
参数说明
备注
numfds
需要监视的文件描述符的最大值+1
readfds
select()监视的读文件描述符集合
writefds
监视的写文件描述符集合
exeptfds
监视的异常处理文件描述符集合
timeout
1) NULL ——永远等待,直到扑捉到信号;
2) 具体值——在等待的时间范围内,没有等到,则立即返回;
3) 0——从不等待,所有文件描述符立即返回
返回值
1) >0:成功,返回准备好的文件描述符的数目;
2) 0:超时;
3) -1:出错;
select() 文件描述符处理函数:
FD_ZERO(fd_set *set); 清除一个文件描述符集;
FD_SET(int fd, fd_set *set); 将文件描述符fd加入到文件描述符集合set中
FD_CLR(int fd, fd_set *set); 将一个文件描述符fd从文件描述符集合中删除;
FD_ISSET(int fd, fd_set *set);
//timeout数据类型介绍:
struct timeval
{
long tv_sec;
long tv_usec;
}
2.2 为什么linux select函数的第一个参数总应该是fdmax + 1 ?
这就涉及到linux select第一个参数的含义: 待测试的描述集的总个数。 但要注意, 待测试的描述集总是从0, 1, 2, ...开始的。 所以, 假如你要检测的描述符为8, 9, 10, 那么系统实际也要监测0, 1, 2, 3, 4, 5, 6, 7, 此时真正待测试的描述符的个数为11个, 也就是max(8, 9, 10) + 1
select 函数注意点:http://blog.csdn.net/jkazan/article/details/52529687
2.3 poll() 函数介绍:
#include
#include
int poll(struct pollfd *fds, int numfds, int timeout);
参数说明:
函数参数
参数说明
备注
fds
struct pollfd结构指针:描述需要对哪些文件的 哪种类型的操作进行监控;
struct pollfd {
int fd;
short events; //要监听的事件
short revents; //已发生的事件
}
events成员描述主要有以下几类:
POLLIN; POLLPRI; POLLOUT; POLLERR; POLLHUP; POLLNVAL;
numfds
要监听的文件描述符个数;
即第一个参数所指向的数组张哦功能的元素数目;
timeout
非0值: 等待的ms数;
<0: 无限等待;
返回值
1) >0:成功,事件发生的pollfd结构的个数;
2) 0:超时;
3) -1:出错;
3. 实例验证:
通过调用select() 函数来监听3个终端的输入,并分别进行相应的处理。3个文件描述符分别是:一个标准输入,两个管道文件描述符;通过监视主程序的输入终端来实现程序控制,比如结束程序;两个管道文件描述符作为输入,主程序将两个管道读取的输入字符串写入到标准输出文件,即屏幕上。
在标准终端输入‘q’ 或者 ’Q’时,监控终端退出,或者60S超时退出。
实验运行结果如下:
创建两个段管道,用命令:mknod in1 mknod in2
管道、网络编程等,都有阻塞作用。
管道中的数据,在下一次select()函数启动的时候,会调用读取管道里面的数据。
3.1 select() 程序代码:
#include
#include
#include
#include
#include
#include
#include
#define MAX_BUFF_SIZE 1024
#define IN_FILES 3
#define TIME_DELAY 60
#define MAX(a, b) ((a > b) ? (a) : (b))
int main(void)
{
int fds[IN_FILES];
char buff[MAX_BUFF_SIZE];
int i, res, real_read, maxfd;
struct timeval tv;
fd_set inset, tmp_inset;
fds[0] = 0;
if( (fds[1] = open("in1", O_RDONLY | O_NONBLOCK)) < 0 )
{ printf("Open in1 is error!
");
return 1;
}
if( (fds[2] = open("in2", O_RDONLY | O_NONBLOCK)) < 0)
{ printf("Open in2 is error!
");
return 1;
}
maxfd = MAX( MAX(fds[0], fds[1]), fds[2]);
FD_ZERO(&inset);
for(i = 0; i < IN_FILES; i++)
{
FD_SET(fds[i], &inset);
}
FD_SET(0, &inset);
tv.tv_sec = TIME_DELAY;
tv.tv_usec = 0;
while( FD_ISSET(fds[0], &inset) || FD_ISSET(fds[1], &inset) || FD_ISSET(fds[2], &inset) )
{
tmp_inset = inset;
//printf("tmp_inset = %d
", tmp_inset);
res = select( maxfd+1, &tmp_inset, NULL, NULL, &tv);
printf("select return res = %d,准备好的fd数目
", res);
switch(res)
{
case -1:{
printf("Select error
");
return 1;
}
break;
case 0:{
printf("Time out
");
return 1;
}
break;
default:{
for(i = 0; i < IN_FILES; i++)
{
if( FD_ISSET(fds[i], &tmp_inset) )
{
memset(buff, 0, MAX_BUFF_SIZE);
real_read = read(fds[i], buff, MAX_BUFF_SIZE);
if(real_read < 0)
{ if(errno != EAGAIN)
return 1;
}
else if( !real_read )
{ close(fds[i]);
FD_CLR(fds[i], &inset);
}
else
{
if( i == 0 )
{
if( (buff[0] = 'q') || (buff[0] == 'Q') )
return 1;
}
else
{
buff[real_read] = '