使用 stdout/stderr 以外的管道与子进程通信
Posted
技术标签:
【中文标题】使用 stdout/stderr 以外的管道与子进程通信【英文标题】:Communicate with a subprocess using pipes on other than stdout/stderr 【发布时间】:2015-02-13 17:46:43 【问题描述】:这就是我 fork/exec 一个子进程并与之通信的方式(伪代码):
int cout_pipe[2];
pipe(cout_pipe);
fork();
if (child)
dup2(cout_pipe[1],STDOUT_FILENO);
execv();
if (parent)
File* cout_file = fdopen(cout_pipe[0], "r");
我的问题是:
我真的不想读取子进程的标准输出,我希望子进程在标准输出以外的文件描述符上写入。而且,我希望从该文件描述符中读取上述代码。
子进程用python写,主进程用C++写。
我想我可以改变那行,从:
dup2(cout_pipe[1],STDOUT_FILENO);
到
dup2(cout_pipe[1],MY_OWN_RANDOM_FD_NUMBER);
并以我写入 MY_OWN_RANDOM_FD_NUMBER 而不是标准输出的方式对子进程进行编码。
这是一个好的解决方案吗?可行吗?我怎样才能找出一个好的 MY_OWN_RANDOM_FD_NUMBER?有更好的选择吗?
【问题讨论】:
【参考方案1】:除非您需要特定的 fd,例如标准输出,否则 dup2
没有任何意义。只需将cout_pipe[1]
转换为字符串,并将其作为命令行参数传递给子进程(在exec
中)。在 Python 端,从sys.argv
中提取参数,将其转换回int
,然后使用os.fdopen
为其获取file
。
【讨论】:
将 cout_pipe[1] 转换为字符串?所以这意味着 pipe(cout_pipe) 使 cout_pipe[1] 成为有效的 fd?。还有什么是转换 itoa(cout_pipe[1]) 的最佳方式? @Kampipe( cout_pipe )
将管道的两个 fd 放入 cout_pipe
。您可能想要使用dup2
的唯一原因是您对 fd 的数值不满意。至于转换,任何标准解决方案都可以解决问题;如果您在子端执行此操作,就在exec
之前,并且您的系统有itoa
(它不是标准的),那么即使这样也是可以接受的;如果您使用的是 C++11,则可以使用 std::to_string
——只需确保在调用 .c_str()
之前将结果保存到具有足够生命周期的变量中即可。【参考方案2】:
在您描述的情况下,无需复制文件描述符。对 pipe() 的调用已经在 cout_pipe 数组中创建了您需要的文件描述符。
通常,子进程在执行之前简单地关闭管道的读取端,而父进程关闭管道的写入端。子进程将它想要的任何内容写入写入端,父进程读取或以其他方式监视管道的读取端。
如果您的问题是“子进程如何知道它执行后的 fd 编号,那么我会说当您在子进程中调用 execv() 时将其作为执行参数传递。”
类似:
int child_pipe[2];
FILE *child_file;
void forkchild(void)
int ret;
char child_pipe_fd_str[16];
pipe(child_pipe); /* TODO: check return value! */
if (0 == (ret = fork())) /* child */
close(child_pipe[0]);
sprintf(child_pipe_fd_str, "%d", child_pipe[1]);
execv(my_python_script, child_pipe_fd_str, NULL);
else if (-1 != ret) /* parent */
close(cout_pipe[1]);
child_file = fdopen(cout_pipe[0], "r");
else
perror("Fork failed!");
abort();
【讨论】:
在上述情况下,当child写入stdout时,stdout之前被重定向到pipe,因此父进程只需从pipe读取即可读取child的stdout。我希望孩子不要写入标准输出,而是写入另一个文件,并且父进程可以读取它。 如果你想将管道的写入端包装在一个文件中,然后在你执行之后在你的子进程中调用 fdopen(write_side, "w")。诀窍是知道您执行的子 AFTER 中管道写入端的文件描述符#。一种方法是在调用 execv() 时将其作为执行参数显式传递。清楚吗? 好的,所以我应该在 fork 之后,exec 之前创建一个 FILE,然后 dup2(cout_pipe[1],this_files_fd),然后将 FILE 的 fd 作为 exec 的参数传递给子进程,并在 python 中我给这个 fd 写信? 不,您应该使用 os.fdopen 在您的新 Python 进程中创建您执行的文件结构 AFTER。诀窍是知道你需要打开什么fd#。您应该将其作为执行参数传递给子 C 进程中的 execv() 。我会在我的答案中发布一些代码。以上是关于使用 stdout/stderr 以外的管道与子进程通信的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Windows 中访问继承的匿名管道句柄,而不是 stdout、stderr 和 stdin?
使用参数 + stdout + stderr 从命令行调用 MFC 应用程序