C++ 在C语言中,当管道输入到另一个程序时,它无法打开
我主要想在C:echo'somestring'| foo中实现这一点,其中foo写入文件file1.txt。运行foo使其阻塞并等待来自stdin的输入,然后写入file1.txt。我正在通过stdin成功地向foo发送数据,但是foo在使用C管道时无法打开本地文件 以下是我所做的:C++ 在C语言中,当管道输入到另一个程序时,它无法打开,c++,c,fork,pipe,fopen,C++,C,Fork,Pipe,Fopen,我主要想在C:echo'somestring'| foo中实现这一点,其中foo写入文件file1.txt。运行foo使其阻塞并等待来自stdin的输入,然后写入file1.txt。我正在通过stdin成功地向foo发送数据,但是foo在使用C管道时无法打开本地文件 以下是我所做的: #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
FILE *stream;
int fds[2];
int status;
pid_t pid;
char *cmd[] = { "foo", NULL };
pipe(fds);
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork failed\n");
return 1;
}
if (pid > 0) {
// Parent process
close(fds[0]);
stream = fdopen(fds[1], "w");
fprintf(stream, "some string\n");
fflush(stream);
close(fds[1]);
waitpid(pid, &status, 0);
if (WIFEXITED(status) == 0 || WEXITSTATUS(status) < 0)
return 1;
}
else {
// Child process
close(fds[1]);
dup2(fds[0], STDIN_FILENO);
execv("foo", cmd);
return 1;
}
return 0;
}
在内部,foo对本地文件进行fopen调用,但失败,错误号为14:EFAULT。我也尝试过使用popen/pclose而不是fork/pipe/dup2/execv来实现这一点
我能做些什么来实现这一点呢?假设foo位于PATH目录中,您可能需要使用execvp。除此之外,您可能需要在execv/full/path/to/foo,cmd中提供完整路径 代码中存在竞争条件。父进程将内容写入管道并将其关闭,而子进程从管道中读取。这可能不是你遇到问题的原因,但这从来都不是一件好事 尝试消除竞争:
stream = fdopen(fds[1], "w");
fprintf(stream, "some string\n");
fflush(stream);
waitpid(pid, &status, 0);
close(fds[1]); // close it when the child process doesn't use it anymore
注意:不管发生什么,都应该使用fclose而不是close
编辑:正如其他人指出的,这个答案是错误的;没有争用条件。我已经检查了foo的代码,并提取了负责从stdin读取和写入文件的部分。您可以在此处查看文件: 我已经确认echo'some string'| foo可以工作,并且运行pipedata程序可以将数据传输到foo并写入文件
由于这个例子一切正常,问题一定出在foo的源代码中的其他地方。stdlib函数popen/pclose是完成这类工作的更简单的方法。他们为你做所有的管道和儿童管理。您的程序将变成:
#include <stdlib.h>
#include <stdio.h>
int main() {
FILE *stream;
if (!(stream = popen("./foo", "w"))) {
fprintf(stderr, "popen failed\n");
return 1;
}
fprintf(stream, "some string\n");
fflush(stream);
if (pclose(stream) < 0) {
fprintf(stderr, "pclose failed\n");
return 1;
}
return 0;
}
如果fopen因EFAULT而失败,是否可以显示fopen代码?没有管道它能工作吗?您确定提供给fopen的文件名有效吗?fopen代码看起来像fopenfile1_name,w,返回NULL。它不用管子就可以工作。提供的文件名有效。如果不想单独显示,可以将包含fopen的代码放入标记为Child process的代码部分foo的源代码很大,我不应该修改它。我们应该将其视为一个库。EFAULT仅表示传递给fopen/fdopen的无效参数,该参数将由EINVAL指示,但表示存在锁定问题。至少在Linux或POSIX确认系统上。完成子项后关闭fds[1]意味着我们永远不会通过stdin将EOF发送给foo。管道需要关闭,以便foo可以继续执行并写入由于fopen调用而失败的文件。这不是竞争条件,可以将内容写入管道并关闭其写入端。无论何时开始读取,管道的读取端都将接收数据和EOF。因为有一个fork调用,closefds[1];很好,孩子仍然有一个参考pipe@MarosHluska实际运行echo“some string”| foo工作吗?i、 e.您是否已将错误隔离在发布的代码中,并确保错误不在foo中。另一份说明;您应该关闭FDS[0];在dup2fds[0]之后的子进程中,STDIN_FILENO,否则,剩下2个文件描述符引用管道的读取端。是的,这样看起来更干净。不过,popen/close和fork/pipe解决方案都造成了问题。我已经发布了一个回复,说我让它工作了。