我正在组建一个类似服务器的进程,它从命名管道接收数据并返回一些输出。
众所周知,当打开管道进行读取时,它会阻止该过程,直到另一个过程打开管道进行写入。 (除非设置了非阻止标志。) 当另一个进程打开管道并写入它时,我们可以得到如下输入:
...
opened_pipe = fopen(argv[1], "r")
while(1)
{
if ( fgets(readbuf, FIFO_READLEN, opened_pipe) != NULL )
{ \\ process the input from the writer }
else
{
\\ this is the branch when the writer closed his end of the pipe and reader gets EOF
\\ usually one exits here
\\ but I would like to freeze the process and wait until another writer comes
\\ (like a server-like application would do)
}
}
但是当作家退出时,while
进入无意义的循环。
如果读者返回到初始状态会更好 - 过程被阻塞,直到管道再次连接到另一端。是否可以这样做?
PS
我尝试在我的程序中创建一个虚拟编写器,它打开与w
相同的管道,并始终在fgets
的循环中保持打开状态。但它对我没有用。也许我做错了。有可能拉这个伎俩吗?
还可以不断关闭并重新打开while
内的管道。但我想使用pipe
或stdin
作为输入流。在程序中以同样的方式对待它们会更好。那么,是否可以通过stdin
使用fopen
文件名重新打开"stdin"
流?
答案 0 :(得分:1)
不确定我完全理解你的问题,但一般来说,当从管道或FIFO(也就是命名管道)读取没有打开书写结束时,您将阅读EOF
。当fgets()
读取EOF
时,这将导致缓冲区中的第一个字节为0
。您可以检查一下,在这种情况下,关闭FIFO并重新打开它,重新进入循环。
类似(坚持使用伪代码段):
while (1)
{
opened_pipe = fopen(argv[1], "r")
while(1)
{
if ( fgets(readbuf, FIFO_READLEN, opened_pipe) == NULL ) {...}
else if (!readbuf[0])
{
fclose(opened_pipe);
break;
}
}
}
编辑:在这里给出您的评论,我得到的印象是您可能想要使用 Unix域套接字而不是 FIFO 。因此,您可以accept()
连接并在等待新连接时单独处理它们。
答案 1 :(得分:1)
只需在服务器进程中打开FIFO两次 - 首先进行读取,然后进行写入。这样做(打开它进行写入)将确保如果所有客户端都放弃FIFO,您的进程将不会看到EOF。
这是简短的演示:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "/tmp/fifo"
int main()
{
if (mkfifo(FIFO_NAME, S_IRUSR | S_IWUSR | S_IWGRP) == -1)
{
perror("mkfifo");
exit(EXIT_FAILURE);
}
FILE *readFd = fopen(FIFO_NAME, "r");
FILE *writeFd = fopen(FIFO_NAME, "w");
char c;
for (;;)
{
c = fgetc(readFd);
fprintf(stdout, "Read char: %c\n", c);
}
}