C、是否可以阻塞进程直到再次打开管道?
C, is it possible to block the process untill the pipe is opened again?
我正在组装一个类似服务器的进程,它从命名管道接收数据和 returns 一些输出。
众所周知,当管道打开进行读取时,它会阻塞进程,直到另一个进程打开管道进行写入。 (除非设置了非阻塞标志。)
当另一个进程打开管道并写入时,我们可以得到这样的输入:
...
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
进入无意义的循环。
如果 reader 返回到初始状态会更好 - 进程将被阻塞,直到管道再次连接到另一端。可以这样做吗?
PS
我试图在我的程序中创建一个虚拟编写器,它打开与 w
相同的管道,并始终在 fgets
的循环中保持打开状态。但这对我不起作用。也许我做错了什么。这招有可能吗?
也可以不断地关闭和重新打开 while
内的管道。但我想使用 pipe
或 stdin
作为输入流。不如在节目中一视同仁。那么,是否可以通过 fopen
使用一些 "stdin"
文件名重新打开 stdin
流?
不确定我完全理解你的问题,但一般来说,当从没有打开写入端的管道或 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 域套接字 而不是 先进先出。因此,您可以 accept()
个连接并在等待新连接的同时单独处理它们。
只需在服务器进程中打开您的 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);
}
}
我正在组装一个类似服务器的进程,它从命名管道接收数据和 returns 一些输出。
众所周知,当管道打开进行读取时,它会阻塞进程,直到另一个进程打开管道进行写入。 (除非设置了非阻塞标志。) 当另一个进程打开管道并写入时,我们可以得到这样的输入:
...
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
进入无意义的循环。
如果 reader 返回到初始状态会更好 - 进程将被阻塞,直到管道再次连接到另一端。可以这样做吗?
PS
我试图在我的程序中创建一个虚拟编写器,它打开与 w
相同的管道,并始终在 fgets
的循环中保持打开状态。但这对我不起作用。也许我做错了什么。这招有可能吗?
也可以不断地关闭和重新打开 while
内的管道。但我想使用 pipe
或 stdin
作为输入流。不如在节目中一视同仁。那么,是否可以通过 fopen
使用一些 "stdin"
文件名重新打开 stdin
流?
不确定我完全理解你的问题,但一般来说,当从没有打开写入端的管道或 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 域套接字 而不是 先进先出。因此,您可以 accept()
个连接并在等待新连接的同时单独处理它们。
只需在服务器进程中打开您的 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);
}
}