Linux pipe读写问题

之前的那个mplayer播放mms电台需要一个控制接口,mplayer只支持控制台输入命令,所以要控制mplayer只能用管道控制标准输入stdin。为了灵活就用FIFO文件作为mplayer的输入端。

mkfifo radio_pipe
cat radio_pipe | mplayer mms://xxx
echo -n p > radio_pipe

这里有个问题是cat radio_pipe读到文件EOF会退出,导致mplayer退出,所以每次只能控制一次:(。

前几天看mini2440附带的led-player程序,突然意识到可以自己写个pipe_read程序忽略文件EOF,这样就解决了mplayer的控制。记得之前写TCP程序时知道read返回0说明到文件EOF了,TCP就代表关闭了。我只要忽略掉read返回0的状态就行了(之后证明大错特错-_-!!!),错误是因为select认为文件EOF是读信号,除非你退出否则一直触发。最后的解决方法是这一句

int null_pipe_write_rd = open(pstrPipe, O_WRONLY | O_NONBLOCK);

再打开一个不操作的pipe读fd,这样才不至返回文件EOF,具体原因不是很明白:(,不过达到了我要的效果:)。

mkfifo radio_pipe
./pipe_read radio_pipe | mplayer mms://xxx
echo -n p > radio_pipe

这样就不会退出了,不过就如我们CEO说的一句话:解决了一个问题,往往带来了其他问题,这样pipe_read永远也不会退出了,尽管mplayer已经退出了-_-!!!。

Talk is cheap, show me the code:

#include <cstdio>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

void usage(const char *pstrProgram)
{
    printf("Usage:\n"
           "  %s pipefile\n", pstrProgram);
}


int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        usage(argv[0]);
        return 1;
    }

    bool bExit = false;
    const char *pstrPipe = argv[1];

    int pipe_rd = open(pstrPipe, O_RDONLY | O_NONBLOCK);
    if (pipe_rd == -1)
    {
        fprintf(stderr, "open pipe fail\n");
        return 1;
    }

    int null_pipe_write_rd = open(pstrPipe, O_WRONLY | O_NONBLOCK);

    while (!bExit)
    {
        fd_set fdset;
        //struct timeval tv;

        FD_ZERO(&fdset);
        FD_SET(pipe_rd, &fdset);

        int ret = select(pipe_rd+1, &fdset, NULL, NULL, NULL);

        if (ret < 0)
        {
            fprintf(stderr, "select return error\n");
            return 1;
        }
        else
        {
            if (FD_ISSET(pipe_rd, &fdset))
            {
                char buffer[128];
                while (true)
                {
                    int nLen = read(pipe_rd, buffer, sizeof(buffer));
                    if (nLen == 0)
                    {
                        fprintf(stderr, "End of file\n");
                        break;
                    }
                    else if (nLen == -1)
                    {
                        if (errno == EAGAIN)
                        {
                            fprintf(stderr, "nonblocking read fail\n");
                        }
                        else
                        {
                            fprintf(stderr, "read fail\n");
                            return 1;
                        }
                        break;
                    }
                    else
                    {
                        // write stdout
                        int ret = write(STDOUT_FILENO, buffer, nLen);
                        if (ret == -1 && errno != EAGAIN)
                        {
                            fprintf(stderr, "write fail\n");
                            return 1;
                        }
                    }
                }
            }
        }
    }

    return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注