如何读取和写入Linux中的fifo(命名管道)?

时间:2017-11-20 19:09:45

标签: c linux named-pipes

我正在尝试打开一个fifo(命名管道)文件,然后写入它。我似乎无法使服务器看到“客户端”写入它的内容。

注意:为了简单起见,我使用“客户端 - 服务器”之类的术语。我意识到他们实际上只是同龄人,任何一方都可以关闭管道。

pipetest_server.c

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

int keep_going = 1;

static void signal_handler(int signum)
{
    keep_going = 0;
}

int main()
{
    int fd;
    char *myfifo = "/tmp/mypipe";
    char *line;
    ssize_t amount_read;
    ssize_t len;
    FILE *f;

    signal(SIGINT, signal_handler);
    signal(SIGABRT, signal_handler);
    signal(SIGTERM, signal_handler);

    // make pipe
    mkfifo(myfifo, 0666);

    // open it
    fd = open(myfifo, O_RDWR);

    // make non-blocking
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

    // make a file descriptor for pipe
    f = fdopen(fd, "rw");

    while(keep_going)
    {
        amount_read = getline(&line, &len, f);
        if (amount_read > 0)
            printf(line);
    }

    printf("quitting...\n");

    close(fd);

    unlink(myfifo);

    return 0;
}

然后:

$ gcc pipetest_server.c
$ ./a.out

在另一个终端:

$ ls -la /tmp/mypipe
prw-rw-r--. 1 myuser myuser 0 Nov 20 12:58 /tmp/mypipe

好的 - 此时,那里有一根烟斗。现在解决问题

1)用echo写入管道。没有任何事情发生

$ echo Hi >> /tmp/mypipe
<nothing comes out of the server>

2)捕捉管道,显示数据

$ cat /tmp/mypipe
Hi
<blinking cursor>

发生了什么......

服务器永远不会获取数据,但管道中包含数据。

3)当我关闭服务器时,管道消失

<ctrl-C>
^Cquitting...

这告诉我服务器确实创建了管道并控制它。

4)我真的想创建另一个写入管道的程序

最终,我希望有另一个程序写入此管道,两个程序将通过它进行通信。

注意:还有其他有关此内容的SO文章,但没有一篇能够说明问题。

更新 - 工作代码

如果有人来,这是最终的解决方案。

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

static volatile sig_atomic_t keep_going = 1;

static void signal_handler(int signum)
{
    keep_going = 0;
}

int main()
{
    int fd;
    char *myfifo = "/tmp/mypipe";
    char *line;
    ssize_t amount_read;
    ssize_t len;
    FILE *f;

    signal(SIGINT, signal_handler);
    signal(SIGABRT, signal_handler);
    signal(SIGTERM, signal_handler);

    // make pipe
    mkfifo(myfifo, 0666);

    // open it
    fd = open(myfifo, O_RDWR);

    // make non-blocking
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

    // make a file descriptor for pipe
    f = fdopen(fd, "rw");

    while(keep_going)
    {
        amount_read = getline(&line, &len, f);
        if (amount_read > 0)
            printf(line);
        if (amount_read == -1)
        {
            clearerr(f);
        }
    }

    printf("quitting...\n");

    close(fd);

    unlink(myfifo);

    return 0;
}

1 个答案:

答案 0 :(得分:2)

问题是您已将文件描述符设置为非阻塞,然后使用fdopen在其上打开FILE *。 Stdio FILE流不理解非阻塞I / O,因此在第一次getline调用时,读取将失败(使用EWOULDBLOCK或EGAIN)并且FILE将进入错误状态,并且getline将返回-1。一旦FILE处于错误状态,每次调用都会立即返回-1而不会再次尝试再次读取。

如果您想实际使用非阻塞模式,则需要在getline返回-1后调用clearerr(f)。您还应该检查错误,以确保错误是EWOULDBLOCK或EAGAIN - 如果出现真正的错误,它将是其他错误。