select 实现多路复用

select 函数简介:
函数所需头文件:
#include < sys/select.h>
函数原型:
int select(int numfds,fd_set *readfds, fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
参数说明:
readfds ,writefds,exceptfds 这三个参数为指定那类文件描述符被监控,每个参数都是一个指向fd_set的指针。
fd_set是一个指向N个数目文件描述符的数据结构。

fd_set操作方法:
1 FD_ZERO(fd_set *fds);//清除fds集合 使fds集合中不包含任何文件描述符,通常用来初始化fd_set结构。
2 FD_SET(int fd,fd_set *fds);// 把fd加入fd_set
3 FD_CLR(int fd,fd_set *fds);// 将fd从fds中清除
4 FD_ISSET(int fd,fd_set *fds);//如果fd在fds中,则返回真
readfds是一个包含有这样的文件描述符的集合:当有数据读取或管道 套接字异常时,将导致select 调用返回;
writefds当有数据写入时,将导致select 调用返回;
exceptfds 监控发生例外情况的文件描述符;
在linux 中,如果不需要监控某一类事件的时候,可以将相应的监控选项放入NULL;
timeout:select 阻塞时间(毫秒)如果此参数设置为NULL ,select将一直阻塞到某个事件的发生。
timeval
struct timeval{
int tv_sec;//秒
int tv_usec;//微秒
}
如果timeval.tv_sec =0;timeval.tv_usec=0; 那么select 不会阻塞会立即返回,直接更新文件描述符集合,返回哪些文件准备好读,那么文件准备好写,然后立即返回。
例:

  #include "fcntl.h"
  #include "stdio.h"
  #include "sys/select.h"
  #include "unistd.h"
  
  int main(void){
    int fds[2];
    char buf[4096];
    int i,rc,maxfd;
    fd_set watchset;
    fd_set inset;
    
      //打开管道
    if((fds[0] =open("p1",O_RDONLY|O_NONBLOCK))<0){
 	 printf("打开管道p1失败!\n");
	 return 0;
     }
	
    if((fds[1]=open("p2",O_RDONLY|O_NONBLOCK))<0){
	printf("打开管道p2失败!\n");
	return 0;
     }
    
    FD_ZERO(&watchset);
    FD_SET(fds[0],&watchset);
    FD_SET(fds[1],&watchset);
   
    maxfd = fds[0] > fds[1]:fds[0]:fds[1];
	
    //阻塞监控数据start
    while(FD_ISSET(fds[0],&watchset) ||
          FD_ISSET(fds[1],&watchset)
         ){
          inset =watchset;
          //采用select 读取start
          if(select (maxfd+1,&inset,NULL,NULL,NULL) <0){
        	printf("select 异常!\n");
		 return 0;
           }
          //采用select 读取end
        
          //获取数据start
 	   for(i=0;i<2;i++){
              if(FD_ISSET(fds[i],&inset){
                   //读数据
                   rc =read(fds[i],buf,sizeof(buf);
		   if(rc <0){
			 printf("读取异常!\n");
			  return 0;	
                       }else
			{
			buf[rc] ='\0';
			printf("读取数据:%s\n",buf);
			}
		   //读数据
               }
            }
          //获取数据end


     } 
   
    //阻塞监控数据end
     return 0;
  }