我正在尝试使用匿名管道替代子进程读取的文件。我遇到的问题是,我认为子流程会挂起,因为它不会识别"文件的结束。 (管道)已经到达。
以下是我正在做的一些示例代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/fcntl.h>
int main()
{
int pipefd[2];
pipe(pipefd);
fcntl(pipefd[0], F_SETFL, O_NONBLOCK); // necessary?
char cmd[128];
snprintf(cmd, sizeof(cmd), "cat /dev/fd/%i", pipefd[0]);
printf("Command: %s\n", cmd);
#if 1
// This works
write(pipefd[1], "line1\n", 6);
write(pipefd[1], "line2\n", 6);
write(pipefd[1], "line3\n", 6);
close(pipefd[1]);
#endif
FILE* fp;
if ((fp = popen(cmd, "r")) != NULL)
{
// fcntl(fileno(fp), F_SETFL, O_NONBLOCK); // causes SIGPIPE
#if 0
// This doesn't work
write(pipefd[1], "line1\n", 6);
write(pipefd[1], "line2\n", 6);
write(pipefd[1], "line3\n", 6);
close(pipefd[1]);
#endif
char buffer[1024];
while (fgets(buffer, sizeof(buffer), fp) != NULL)
printf("%s", buffer);
printf("retcode: %i\n", pclose(fp));
}
close(pipefd[0]);
return 0;
}
上面给出的代码有效。在其中我创建了一个管道,并使用管道的读取端创建一个命令,在本例中为cat
。在工作版本中,然后我将数据写入管道的写入端然后使用popen
启动子流程并从子流程读取stdout直到它结束。
我需要做的是在创建子流程之后将写入移动到管道(请参阅#if 0
块)。最终,它将最终成为一个单独的线程。但是,切换到popen
通话后意味着子流程不会结束(挂起),我看不清楚原因。
我已尝试使各种流非阻塞,但在子流程流上执行此操作只会导致SIGPIPE失败。
有谁知道如何使这个工作?
谢谢!
答案 0 :(得分:0)
做
之间的区别write(pipefd[1], "line1\n", 6);
write(pipefd[1], "line2\n", 6);
write(pipefd[1], "line3\n", 6);
close(pipefd[1]);
在popen vs after之前的是这样的:如果在调用popen时打开pipefd[1]
,forked / execed进程也将打开它。当该进程从pipefd[0]
读取时,它将永远不会看到EOF,因为该描述符(管道的写入端)保持打开状态。
解决此问题的一个方法是为该文件描述符设置close-on-exec标志
fcntl(pipefd[1], F_SETFD, fcntl(pipefd[1], F_GETFD) | FD_CLOEXEC);
在打电话给popen之前。