如何读写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——如果存在真正的错误,那将是其他错误。
我正在尝试打开一个 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——如果存在真正的错误,那将是其他错误。