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。

#include <fcntl.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <string.h>  
#include <time.h>  
#include <errno.h>  

#define FIFO1 "in1"  
#define FIFO2 "in2"  
#define MAX_BUFFER_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];      //管道描述符  
    int i;  
    int res;  
    int real_read;  
    int maxfd;  

    char buf[MAX_BUFFER_SIZE];  

    struct timeval tv;  

    fd_set inset;  
    fd_set tmp_inset;           //文件描述符集  

    fds[0] = 0;          //终端的文件描述符  

    if(access(FIFO1,F_OK) == -1)         //创建两个有名管道  
    {  
        if((mkfifo(FIFO1,0666) < 0) && (errno != EEXIST))  
        {  
            printf("Cannot creat fifo1 file!\n");  

            exit(1);  
        }  
    }  

    if(access(FIFO2,F_OK) == -1)  
    {  
        if((mkfifo(FIFO2,0666) < 0) && (errno != EEXIST))  
        {  
            printf("Cannot creat fifo2 file\n");  

            exit(1);  
        }  
    }  

    if((fds[1] = open(FIFO1,O_RDONLY | O_NONBLOCK)) < 0)   //以只读非阻塞的方式打开两个管道文件  
    {  
        printf("open in1 error!\n");  

        return 1;  
    }  

    if((fds[2] = open(FIFO2,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);     //将insert清零,使集合中不含任何fd  
    for(i = 0; i < IN_FILES; i++)  
    {  //将fds[i]加入inset集合  
        FD_SET(fds[i],&inset);  
    }  

    FD_SET(0,&inset);  

    tv.tv_sec = TIME_DELAY;   //设置超时60s  
    tv.tv_usec = 0;  
//循环测试该文件描述符是否准备就绪,并调用selelct()函数对相关文件描述符做相应的操作  
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 != EAGAIN)  
                                {  
                                    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;
 }

这里写图片描述这里写图片描述
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值