我有一个循环。在此循环中,我尝试使用select()
检测是否在命名管道(FIFO)文件上触发了读取或写入操作。
如果触发了读取,则在FIFO文件描述符上调用read()
。
如果触发了写操作,则在FIFO文件描述符上调用write()
。
问题是,如果发生写操作并且我写FIFO,它将触发读操作。然后,当我从FIFO读取数据时,它将触发写操作。造成无限循环。
如果我在模式O_RDWR
中使用相同的文件描述符,则会立即发生此循环。如果我为读取和写入创建了单独的文件描述符,则会在第一次写入之后发生此循环。
#include <errno.h>
#include <sys/select.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
int main() {
// Open export fifo
int fd = open("./foo-fifo", O_RDWR | O_CREAT);
if (fd < 0) { // Failed to open
perror("error opening fifo");
}
// Read or write fifo until "quit" is in buffer
while (true) {
fd_set read_fds;
fd_set write_fds;
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
FD_ZERO(&write_fds);
FD_SET(fd, &write_fds);
int num_fds = select(fd+1, &read_fds, &write_fds, NULL, NULL);
if (num_fds < 0) { // Failed to select
perror("failed to select fifo fd");
} else if (num_fds == 0) { // Timeout
continue;
}
// If read
if (FD_ISSET(fd, &read_fds)) {
char buf[1000] = "";
if (read(fd, buf, sizeof(buf)) < 0) {
perror("error reading fifo");
}
printf("read: \"%s\"\n", buf);
if (strcmp(buf, "quit\n") == 0) {
break;
}
}
// If write
if (FD_ISSET(fd, &write_fds)) {
char *buf = "foo";
if (write(fd, buf, sizeof(buf)) < 0) {
perror("error writing fifo");
}
printf("write: \"%s\"\n", buf);
}
}
// Close fifo
if (close(fd) < 0) { // Failed to close
perror("failed to close export fifo");
}
return 0;
}
通过下载代码from here (GitHub Gist)来运行示例。然后运行:
gcc -o fifo fifo.c
./fifo
输出将显示读写之间的循环:
write: "foo"
read: ""
write: "foo"
read: ""
write: "foo"
...
答案 0 :(得分:0)
注意:这是我的主要评论开头。
我们需要两个进程(例如服务器和客户端)。
fifos是单向的(作家和读者),不是像插座。
因此,要使用fifos进行此操作,您将需要两个。 (例如)给定进程A和B,我们需要两个管道/ FIFO:pipeAB
和pipeBA
。
进程A写入pipeAB
,而B从pipeAB
读取。
进程B写入pipeBA
,而进程A从pipeBA
读取
如果要使用套接字,可以执行PF_UNIX
(也称为AF_UNIX
)套接字。参见man 7 unix
和man 2 socketpair
。
或者,您可以使用功能固定的端口号将主机设置为localhost来创建完整的AF_INET套接字。
作为一项练习[适合您],请考虑以几种方式进行。也就是说,有argv
选项,如双管道的-Tp
,AF_UNIX的-Tu
和AF_INET的-Ts
,等等。只有初始化是不同的。否则该协议将几乎相同。
对于AF_UNIX
套接字,如果客户端和服务器是不同的程序,则在文件系统中创建套接字类型的文件可能会更容易。这可以通过在“ struct sockaddr_un
”中填写“文件名”,然后在bind
调用之后使用socket
来完成。参见:https://www.ibm.com/support/knowledgecenter/en/SSB23S_1.1.0.13/gtpc1/unixsock.html为例