从linux和OS X中的命名管道读取

时间:2014-01-07 00:20:45

标签: c linux macos posix named-pipes

下面的程序在OS X下运行良好,但在linux中运行不正常。它继续循环遍历perror(“读错误”)行,读缓冲区中没有字节,EWOULDBLOCK不是errno(errno = 0);

在OS X中,程序按预期工作,即从三个命名管道读取,并将任何数据打印到控制台。

        #include <sys/types.h>
        #include <sys/select.h>
        #include <sys/time.h>
        #include <sys/types.h>
        #include <errno.h>
        #include <stdlib.h>
        #include <stdio.h>
        #include <fcntl.h>
        #include <unistd.h>


        int readPipe(int fd)
        {
            ssize_t bytes;
            size_t total_bytes = 0;
            char buffer[100*1024];

            printf("\nReading pipe descriptor # %d\n",fd);
            for(;;) {
                bytes = read(fd, buffer, sizeof(buffer));
                if (bytes > 0) {
                    total_bytes += (size_t)bytes;
                    printf("%s", buffer);
                } 
                else {
                    if (errno == EWOULDBLOCK) {
                        break; // recieve buffer is empty so return to main loop
                    } 
                    else {
                        perror("read error"); 
                        return EXIT_FAILURE;
                    }
                }
            }
            return EXIT_SUCCESS;
        }


        int main(int argc, char* argv[])
        {
            int fd_a, fd_b, fd_c;   // file descriptors for each pipe
            int nfd;                // select() return value
            fd_set read_fds;        // file descriptor read flags
            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = 10000;

            // create pipes to monitor (if they don't already exist)
            system("mkfifo /tmp/PIPE_A");
            system("mkfifo /tmp/PIPE_B");
            system("mkfifo /tmp/PIPE_C");
            system("chmod 666 /tmp/PIPE_*");

            // open file descriptors of named pipes to watch
            fd_a = open("/tmp/PIPE_A", O_RDONLY | O_NONBLOCK); // the O_RDWR flag is undefined on a FIFO.
            if (fd_a == -1) {
                perror("open error");
                return EXIT_FAILURE;
            }

            fd_b = open("/tmp/PIPE_B", O_RDONLY | O_NONBLOCK);
            if (fd_b == -1) {
                perror("open error");
                return EXIT_FAILURE;
            }

            fd_c = open("/tmp/PIPE_C", O_RDONLY | O_NONBLOCK);
            if (fd_c == -1) {
                perror("open error");
                return EXIT_FAILURE;
            }

            // check for new data in each of the pipes
            for(;;)
            {
                // clear fds read flags
                FD_ZERO(&read_fds);

                // PIPE_A
                FD_SET(fd_a, &read_fds);
                nfd = select(fd_a+1, &read_fds, NULL, NULL, &tv);
                if (nfd != 0) {
                    if (nfd == -1) {
                        perror("select error");
                        return EXIT_FAILURE;
                    }
                    if (FD_ISSET(fd_a, &read_fds)) {
                        readPipe(fd_a);
                    }
                }

                // PIPE_B
                FD_SET(fd_b, &read_fds);
                nfd = select(fd_b+1, &read_fds, NULL, NULL, &tv);
                if (nfd != 0) {
                    if (nfd == -1) {
                        perror("select error");
                        return EXIT_FAILURE;
                    }
                    if (FD_ISSET(fd_b, &read_fds)){
                        readPipe(fd_b);
                    }
                }

                // PIPE_C
                FD_SET(fd_c, &read_fds);
                nfd = select(fd_c+1, &read_fds, NULL, NULL, &tv);
                if (nfd != 0) {
                    if (nfd == -1) {
                        perror("select error");
                        return EXIT_FAILURE;
                    }
                    if (FD_ISSET(fd_c, &read_fds)){
                        readPipe(fd_c);
                    }
                }
            }
            return EXIT_SUCCESS;
        }

1 个答案:

答案 0 :(得分:3)

允许(并且预期)读取可以返回0.这意味着管道返回EOF。你没有处理这个条件。除非调用失败并返回-1,否则errno的内容无关紧要。

for (;;)
{
    bytes = read(fd, buffer, sizeof(buffer));

    if (bytes > 0)
    {
        total_bytes += (size_t)bytes;
        printf("%s", buffer);
    }

    if (bytes == 0)
        return //something appropriate

    if (bytes == -1)
    {
        if (errno == EWOULDBLOCK)
           break; // recieve buffer is empty so return to main loop
        else
        {
            perror("read error");
            return EXIT_FAILURE;
        }
    }
}

您正在努力返回不同的代码,但您在main中没有注意到它们。

另外,3 select语句又是什么?我以为在前一个问题中已经解决了这个问题。

修改

for (;;)
{
    // clear fds read flags
    FD_ZERO(&read_fds);
    FD_SET(fd_a, &read_fds);
    FD_SET(fd_b, &read_fds);
    FD_SET(fd_c, &read_fds);

    tv.tv_sec = 0;
    tv.tv_usec = 10000;

    nfd = select(fd_c + 1, &read_fds, NULL, NULL, &tv);

    if (nfd == 0) //timeout - continue or do something else for a bit
        continue;

    if (nfd == -1)
    {
        perror("select error");
        return EXIT_FAILURE;
    }

    if (FD_ISSET(fd_a, &read_fds))
        readPipe(fd_a);

    if (FD_ISSET(fd_b, &read_fds))
        readPipe(fd_b);

    if (FD_ISSET(fd_c, &read_fds))
        readPipe(fd_c);
}