Select函数使我们可以执行I/O多路转接,传向select的参数告诉内核:
1、我们所关心的描述法
2、对于每个描述符我们关心的状态
3、愿意等待的时间
4、已准备好的描述符的数量
5、对于读写或异常三个状态中的哪一个已准备好
函数原型:
Int select(int maxfdp1,fd_set *readfds,fd_set *writefds,fd_set *exeptfds,struct timeval *timeout)
/*
**主要实现通过调用select函数监听3个终端输入,并分别做相应的处理,
建立了3个读文件描述符,通过监视主程序的虚拟终端标准输入来实现程序的控制,
以两个管道昨为数据输入,主程序将从两个管道读取输入数据写入到标准输出文件
*/
/*multiplex_select*/
#include<fcntl.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<time.h>
#include<sys/select.h>
#include<errno.h>
#define IN_FILES 3 /*多路复用输入文件数目*/
#define MAX(a,b) ((a>b)?(a):(b))
#define TIME_DELAY 60
#define MAX_BUFFER_SIZE 1024
int main(void)
{
int fds[IN_FILES];
char buf[MAX_BUFFER_SIZE];
int maxfd;
int i,res; //res是返回准备好的文件描述符数目
fd_set inset,tmp_inset; //声明读集合描述符
struct timeval tv;
int real_read;
/*首先以只读非阻塞方式打开两个管道文件*/
fds[0]=0;
if((fds[1]=open("in1",O_RDONLY | O_NONBLOCK))<0)
{
printf("open in1 error\n");
return 1;
}
if((fds[2]=open("in2",O_RDONLY | O_NONBLOCK))<0)
{
printf("open in2 error\n");
return 1;
}
/*取出两个文件描述符中的较大者*/
maxfd=MAX(MAX(fds[0],fds[1]),fds[2]);
/*初始化读集合inset,并在读集合汇总加入相应的描述符集*/
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;
/*循环测试该文件描述符是否准备就绪,并调用select函数对相关文件描述符做对应操作*/
while(FD_ISSET(fds[0],&inset) || FD_ISSET(fds[1],&inset) || FD_ISSET(fds[2],&inset))
{
/*文件描述符集合的备份,这样可以避免每次进行初始化*/
tmp_inset=inset;
res=select(maxfd+1,&tmp_inset,NULL,NULL,&tv);
switch(res)
{
case -1:
{
printf("Select error\n");
return 1;
}
break;
case 0: /*超时*/
{
printf("Time out\n");
return 1;
}
break;
default:
{
for(i=0;i<IN_FILES;i++)
{
if(FD_ISSET(fds[i]),&tmp_inset)
{
memset(buf,0,MAX_BUFFER_SIZE);
real_read=read(fds[i],buf,MAX_BUFFER_SIZE);
if(real_read<0)
{
if(errno !=EAGIN)
return 1;
}
else if(!real_read)
{
close(fds[i]);
FD_CLR(fds[i],&inset);
}
else
{
if(i==0)
{
/*主程序终端控制*/
if((buf[0]=='q') || buf[0]=='Q')
return 1;
}
else
{
/*显示管道输入字符串*/
buf[real_read]='\0';
printf("%s",buf);
}
}
}
}
}
break;
}
}
return 0;
}