从两个管道中无限读取,然后在C中的stdout上打印

时间:2011-11-21 13:24:46

标签: c pipe stdout

我有两个管道,它们都在随机点获得不同的数据。我想要的是将两个管道中的内容打印到 stdout

              __________________
   pipe1     |                  |
]==============>               -----------.
             |                  |          \
             |     process1     |           -----> stdout
   pipe2     |                  |          /
]==============>               -----------´
             |__________________|

我的代码在process1中查看了这个:

while (1) {
  read(pipe1[0], &buff, sizeof(char));  
  write(1, &buff, sizeof(char));
  read(pipe2[0], &buff2, sizeof(char)); 
  write(1, &buff2, sizeof(char));
}

然而,这不起作用,因为当数据来自另一个管道时,可以阻止一个read()(如果没有数据到来)。

如何从两个管道中同时打印同时而不会在一个管道中被阻止?或者关于如何解决这个问题的任何其他建议都是受欢迎的。

2 个答案:

答案 0 :(得分:3)

使用select在两个套接字上等待。数据准备就绪后,它会告诉您哪些管道有可用的数据。

void setnonblocking(int fd) {
    int opts;

    opts = fcntl(fd,F_GETFL);
    if (opts < 0) {
        perror("Couldn't get file descriptor flags");
        exit(EXIT_FAILURE);
    }
    opts = (opts | O_NONBLOCK);
    if (fcntl(fd,F_SETFL,opts) < 0) {
        perror("Couldn't set file descriptor to non-blocking");
        exit(EXIT_FAILURE);
    }
    return;
}

#ifndef BUFSIZE
#  define BUFSIZE 1024
#endif
void cat(fd_set* waiting, int fd) {
   static char buf[BUFSIZE];

   int readCnt;
   if (FD_ISSET(fd, waiting)) {
       while ((readCnt = read(fd, buf, BUFSIZE)) > 0) {
           write(stdout, buf, readCnt);
       }
       if (readCnt < 0) {
           perror("Error reading from pipe");
       }
   }
}

...
{
    fd_set pipes, readable;

    setnonblocking(pipes1[0]);
    setnonblocking(pipes2[0]);

    FD_ZERO(&pipes);
    FD_SET(pipe1[0],&pipes);
    FD_SET(pipe2[0],&pipes);

    int ready;
    while (1) {
        if ((ready = select(2, &pipes, NULL, NULL, NULL)) > 0) {
            cat(&pipes, pipe1[0]);
            cat(&pipes, pipe2[0]);
        } else {
            // no time limit, so there was an error
            perror("Error waiting for input");
            exit(EXIT_FAILURE);
        }
        FD_SET(pipe1[0],&pipes);
        FD_SET(pipe2[0],&pipes);
    }
}

注意上面的内容会永远运行,除非出现错误。您可能希望程序在某个时刻停止。

答案 1 :(得分:2)

您需要多路复用输入。相关的系统调用是pollselect(或ppollpselect)。 select tutorial对于阅读非常有用。