FIFO:一个进程从不从管道中读取
Posted
技术标签:
【中文标题】FIFO:一个进程从不从管道中读取【英文标题】:FIFO: One process never reads from pipe 【发布时间】:2020-06-17 08:50:14 【问题描述】:我正在关注THISTutorialsPoint 的 Linux 管道指南,我特别需要使用 FIFO。
但是,代码在服务器端根本不起作用。
服务器文件要么无限期挂起,要么什么也不读取,而客户端则在 FIFO 上写入并立即读取它刚刚写入的内容。
这是两个文件的完整代码,以防您不想通过 TutorialsPoint:
fifoserver_twoway.cpp
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
void reverse_string(char *);
int main()
int fd;
char readbuf[80];
char end[10];
int to_end;
int read_bytes;
/* Create the FIFO if it does not exist */
mkfifo(FIFO_FILE, S_IFIFO|0640);
strcpy(end, "end");
fd = open(FIFO_FILE, O_RDWR);
while(1)
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOSERVER: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
to_end = strcmp(readbuf, end);
if (to_end == 0)
close(fd);
break;
reverse_string(readbuf);
printf("FIFOSERVER: Sending Reversed String: \"%s\" and length is %d\n", readbuf, (int) strlen(readbuf));
write(fd, readbuf, strlen(readbuf));
/*
sleep - This is to make sure other process reads this, otherwise this
process would retrieve the message
*/
sleep(2);
return 0;
void reverse_string(char *str)
int last, limit, first;
char temp;
last = strlen(str) - 1;
limit = last/2;
first = 0;
while (first < last)
temp = str[first];
str[first] = str[last];
str[last] = temp;
first++;
last--;
return;
fifoclient_twoway.cpp
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
int main()
int fd;
int end_process;
int stringlen;
int read_bytes;
char readbuf[80];
char end_str[5];
printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n");
fd = open(FIFO_FILE, O_CREAT|O_RDWR);
strcpy(end_str, "end");
while (1)
printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
end_process = strcmp(readbuf, end_str);
//printf("end_process is %d\n", end_process);
if (end_process != 0)
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOCLIENT: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
else
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
close(fd);
break;
return 0;
当我运行这两个进程时,我得到的是:
./fifoserver_twoway
FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0
FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0
./fifoclient_twoway
FIFOCLIENT: Sent string: "ciao" and string length is 4
FIFOCLIENT: Received string: "ciao" and length is 4
Enter string: why won't you reverse?
FIFOCLIENT: Sent string: "why won't you reverse?" and string length is 29
FIFOCLIENT: Received string: "why won't you reverse?" and length is 29
还值得注意的是,在开始写这个问题之前,服务器的行为是完全不同的:不像你在这里看到的那样接收和打印,它会在“读取”之后无限期挂起(而且我没有改变编码一位,除了改变 FIFO_FILE 路径)
【问题讨论】:
如果管道为空,则读取将阻塞。您的客户似乎正在阅读它写入管道的消息。使用 2 根管道。服务器从管道 1 读取并写入管道 2。客户端首先写入管道 1,然后等待管道 2 上的响应。 @TonyTannous 我会试一试的。但是 FIFO 不应该专门用于 2 路通信吗?您的建议可能会起作用,但似乎是对 FIFO 应该首先解决的问题的修复 您可以使用同步方法来确保服务器先读取而不是客户端读取。 打开fifo后client中fd的值是多少?它也可能失败。 离题:readbuf[read_bytes] = '\0';
如果您读入整个缓冲区,则会产生未定义的行为!
【参考方案1】:
你让服务器在写完之后休眠——而不是客户端。这样,客户端仍然可能会在服务器获取它之前读回它自己的输出。所以至少你应该在两次写入之后添加一个睡眠,让服务器睡眠更长时间,以确保客户端首先醒来读取服务器输出。
同时访问未命名管道(通过pipe functions 创建)的同一端是未定义的行为。虽然不确定命名管道,但我认为那里也几乎相同。通过简单的延迟(sleep
、usleep
)同步对这些目的的并发访问可能会奏效,但这是一种非常不安全的方法。
我宁愿推荐两个单独的管道(正如 Tony Tannous 已经建议的那样),每个方向一个(根据需要打开各自的末端 RDONLY
或 WRONLY
),然后您将获得全双工通信而不是半双工通信双工,您也不需要进一步同步(最简单的变体延迟):
// server
int fd_cs = open(FIFO_FILE_CS, O_RDONLY);
int fd_sc = open(FIFO_FILE_SC, O_WRONLY);
read(fd_cs, ...);
write(fd_sc, ...);
// client
int fd_cs = open(FIFO_FILE_CS, O_WRONLY);
int fd_sc = open(FIFO_FILE_SC, O_RDONLY);
write(fd_cs, ...);
read(fd_sc, ...);
【讨论】:
以上是关于FIFO:一个进程从不从管道中读取的主要内容,如果未能解决你的问题,请参考以下文章