【问题标题】:Communicate with a subprocess using pipes on other than stdout/stderr使用 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?有更好的选择吗?

【问题讨论】:

    标签: python c++ linux


    【解决方案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]) 的最佳方式?
    • @Kam pipe( 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() 。我会在我的答案中发布一些代码。
    猜你喜欢
    • 1970-01-01
    • 2014-02-14
    • 2012-05-20
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 2020-09-21
    • 2021-03-20
    • 2023-04-06
    相关资源
    最近更新 更多