Linux C——poll函数实现多路复用

多路复用

   多路复用一般用于I/O操作可能会被阻塞的情况,对可能会有阻塞的I/O的管道、网路进行编程。

采用管道函数创建有名管道,使用select函数替代使用poll函数实现多路复用: 创建两个有名管道,获取3个文件描述符(2个管道1个标准输入),然后初始化读文件描述符,select监视文件描述符的文件读写,管道1输出到屏幕上,管道2输出到屏幕上,标准输入‘Q’来进行判读是否退出。

 

select参数函数介绍:

(1)第一个参数maxfdp1指定待测试的描述字个数,它的值是待测试的最大描述字加1(因此把该参数命名为maxfdp1),描述字0、1、2...maxfdp1-1均将被测试。

因为文件描述符是从0开始的。

(2)中间的三个参数readset、writeset和exceptset指定我们要让内核测试读、写和异常条件的描述字。如果对某一个的条件不感兴趣,就可以把它设为空指针。struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符,可通过以下四个宏进行设置:

          void FD_ZERO(fd_set *fdset);           //清空集合

          void FD_SET(int fd, fd_set *fdset);   //将一个给定的文件描述符加入集合之中

          void FD_CLR(int fd, fd_set *fdset);   //将一个给定的文件描述符从集合中删除

          int FD_ISSET(int fd, fd_set *fdset);   // 检查集合中指定的文件描述符是否可以读写 

(3)timeout告知内核等待所指定描述字中的任何一个就绪可花多少时间。其timeval结构用于指定这段时间的秒数和微秒数。

         struct timeval{

                   long tv_sec;   //seconds

                   long tv_usec;  //microseconds

       };

这个参数有三种可能:

(1)永远等待下去:仅在有一个描述字准备好I/O时才返回。为此,把该参数设置为空指针NULL。

(2)等待一段固定时间:在有一个描述字准备好I/O时返回,但是不超过由该参数所指向的timeval结构中指定的秒数和微秒数。

(3)根本不等待:检查描述字后立即返回,这称为轮询。为此,该参数必须指向一个timeval结构,而且其中的定时器值必须为0。

[html]  view plain  copy
  1. <span style="font-family:FangSong_GB2312;font-size:18px;"><strong>#include <fcntl.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <unistd.h>  
  5. #include <string.h>  
  6. #include <time.h>  
  7. #include <errno.h>  
  8.    
  9. #define FIFO1 "in1"  
  10. #define FIFO2 "in2"  
  11. #define MAX_BUFFER_SIZE 1024  //缓冲区大小  
  12. #define IN_FILES 3               //多路复用输入文件数目  
  13. #define TIME_DELAY 60           //超时秒数  
  14.    
  15. #define MAX(a,b) ((a > b) ? (a) : (b))  
  16.    
  17. int main(void)  
  18. {  
  19.     int fds[IN_FILES];      //管道描述符  
  20.     int i;  
  21.     int res;  
  22.     int real_read;  
  23.     int maxfd;  
  24.    
  25.     char buf[MAX_BUFFER_SIZE];  
  26.    
  27.     struct timeval tv;  
  28.    
  29.     fd_set inset;  
  30.     fd_set tmp_inset;           //文件描述符集  
  31.    
  32.     fds[0] = 0;          //终端的文件描述符  
  33.    
  34.     if(access(FIFO1,F_OK) == -1)         //创建两个有名管道  
  35.     {  
  36.         if((mkfifo(FIFO1,0666) < 0) && (errno != EEXIST))  
  37.         {  
  38.             printf("Cannot creat fifo1 file!\n");  
  39.    
  40.             exit(1);  
  41.         }  
  42.     }  
  43.    
  44.     if(access(FIFO2,F_OK) == -1)  
  45.     {  
  46.         if((mkfifo(FIFO2,0666) < 0) && (errno != EEXIST))  
  47.         {  
  48.             printf("Cannot creat fifo2 file\n");  
  49.    
  50.             exit(1);  
  51.         }  
  52.     }  
  53.    
  54.     if((fds[1] = open(FIFO1,O_RDONLY | O_NONBLOCK)) < 0)   //以只读非阻塞的方式打开两个管道文件  
  55.     {  
  56.         printf("open in1 error!\n");  
  57.    
  58.         return 1;  
  59.     }  
  60.    
  61.     if((fds[2] = open(FIFO2,O_RDONLY | O_NONBLOCK)) < 0)  
  62.     {  
  63.         printf("open in2 error!\n");  
  64.    
  65.         return 1;  
  66.     }  
  67.    
  68.     maxfd = MAX(MAX(fds[0],fds[1]),fds[2]);  //取出两个文件描述符中的较大者  
  69.    
  70.     //初始化读集inset,并在读文件描述符集中加入相应的描述集  
  71.     FD_ZERO(&inset);     //将insert清零,使集合中不含任何fd  
  72.     for(i = 0; i < IN_FILES; i++)  
  73.     {  //将fds[i]加入inset集合  
  74.         FD_SET(fds[i],&inset);  
  75.     }  
  76.    
  77.     FD_SET(0,&inset);  
  78.    
  79.     tv.tv_sec = TIME_DELAY;   //设置超时60s  
  80.     tv.tv_usec = 0;  
  81. //循环测试该文件描述符是否准备就绪,并调用selelct()函数对相关文件描述符做相应的操作  
  82. while(FD_ISSET(fds[0],&inset) || FD_ISSET(fds[1],&inset) || FD_ISSET(fds[2],&inset))  
  83.     {    //文件描述符集的备份,以免每次都进行初始化  
  84.         tmp_inset = inset;  
  85.         res = select(maxfd+1,&tmp_inset,NULL,NULL,&tv);  
  86.    
  87.         switch(res)  
  88.         {  
  89.             case -1:  
  90.                 {  
  91.                     printf("Select error!\n");  
  92.    
  93.                     return 1;  
  94.                 }  
  95.                 break;  
  96.    
  97.             case 0:  
  98.                 {  
  99.                     printf("Time out!\n");  
  100.    
  101.                     return 1;  
  102.                 }  
  103.                 break;  
  104.             default:  
  105.                 {  
  106.                     for(i = 0; i < IN_FILES; i++)  
  107.                     {  
  108.                         if(FD_ISSET(fds[i],&tmp_inset))  
  109.                         {  
  110.                             memset(buf,0,MAX_BUFFER_SIZE);  
  111.    
  112.                             real_read = read(fds[i],buf,MAX_BUFFER_SIZE);  
  113.    
  114.                             if(real_read < 0)  
  115.                             {  
  116.                                 if(errno != EAGAIN)  
  117.                                 {  
  118.                                     return 1;  
  119.                                 }  
  120.                             }  
  121.                             else if(!real_read)  //已到达文件尾  
  122.                             {  
  123.                                 close(fds[i]);  
  124.    
  125.                                 FD_CLR(fds[i],&inset);  
  126.                             }  
  127.                             else  
  128.                             {  
  129.                                 if(i == 0)  
  130.                                 {   //主程序终端控制  
  131.                                     if((buf[0] == 'q') || (buf[0] == 'Q'))  
  132.                                     {  
  133.                                         return 1;  
  134.                                     }  
  135.                                 }  
  136.                                 else  
  137.                                 {   //显示管道输入字符串  
  138.                                     buf[real_read] = '\0';  
  139.    
  140.                                     printf("%s",buf);  
  141.                                 }  
  142.                             }  
  143.                         }  
  144.                     }  
  145.                 }  
  146.              break;  
  147.         }  
  148.     }  
  149.    
  150.     return 0;  
  151. }strong>span>  
Linux C——poll函数实现多路复用_第1张图片

你可能感兴趣的:(Linux系统基础)