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

How to read and write to a fifo (named pipe) in Linux?

我正在尝试打开一个 fifo(命名管道)文件,然后写入。我似乎无法让服务器看到 "client" 写入的内容。

注意:为简单起见,我使用 "client-server" 之类的术语。我意识到他们实际上只是同行,任何一方都可以关闭管道。

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

OK -- 此时,那里有一个管道。现在解决问题

1) 用回显写入管道。什么都没发生

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

2) Cat'ing the pipe, shows the data

$ cat /tmp/mypipe
Hi
<blinking cursor>

发生了什么....

服务器从未获取数据,但管道中有数据。

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

<ctrl-C>
^Cquitting...

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

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

最终,我想要另一个程序写入这个管道,这两个程序将通过它进行通信。

注意:还有其他关于此的 SO 文章,但 none 只是切中要点。

更新 -- 工作代码

这是最后的解决方案,以防万一。

#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;
}

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

如果要真正使用非阻塞模式,需要在getlinereturns -1之后调用clearerr(f)。您还应该检查 errno,以确保错误是 EWOULDBLOCK 或 EAGAIN——如果存在真正的错误,那将是其他错误。