[Linux C编程]多路复用

多路复用

   多路复用一般用于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。

<span style="font-family:FangSong_GB2312;font-size:18px;"><strong>#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;
}</strong></span>



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值