【问题标题】:Using pipe() after child calls exec()在子调用 exec() 后使用 pipe()
【发布时间】:2016-01-12 19:18:16
【问题描述】:

我的最终目标是让父进程将文本行传递给子进程,然后子进程会将文本打印到标准输出。孩子将在后台“永久”运行,而父母获取用户输入并将其传递给孩子。我更喜欢在单独的程序中的孩子。通过 if 语句区分 child 和 paretn 就像软糖一样混乱。

我正在研究管道,但我不确定在孩子将exec() 调用到另一个程序之后,管道是否可以在父/子之间进行通信。

这可能吗?如果是这样,你有什么例子可以指点我吗?如果没有,那我可以使用哪种 IPC 方法?

【问题讨论】:

  • 我想我是操之过急,很乐意移除我的 cmets - 这会让 @amon 显得很奇怪。很高兴看到您得到答复。
  • @amon - 我正在删除我的 cmets(见上面的评论)
  • 谢谢凯文。不用担心。我也将删除我的。

标签: c pipe exec parent-child ipc


【解决方案1】:

标准方案是让作为孩子执行的程序与管道无关,只使用stdin / stdout。您可以通过dup2()将管道的相应端作为fd 01(或两者都有用于双向通信的两个管道)来实现这一点,对应于STDIN_FILENOSTDOUT_FILENO。在此之后,执行您的子程序。

当然,还有其他选择,例如“命名管道”如果您需要 stdin / stdout 用于孩子的不同目的。

如果您自己编写这两个部分,您可能需要考虑更简单的解决方案:

通过 if 语句来区分子级和父级是一团糟。

无论如何你都必须这样做,至少是为了连接管道和调用 exec()。只需创建单独的代码文件并酌情调用parent_main()child_main() 之类的东西(无论你喜欢如何称呼它们)。

【讨论】:

  • 谢谢,您的回答正是我所需要的。谢谢你。我喜欢你简化父子关系的方式,让它看起来不像我最初想象的那样凌乱。
【解决方案2】:

在 exec*() 函数之后,子进程共享父进程的所有文件描述符。所以如果你在 fork() 之前创建一个管道,你就可以在它们中读/写 fd。

通常的方法是:

  • 创建管道(读取 fd,写入 fd)
  • fork()
  • 在父级中:
    • close read fd(你不会在这里从父级读取)
    • 将数据写入write fd
    • 等待/死亡
  • 在儿童中:
    • 关闭写 fd(你不会从孩子写)
    • 从 read fd 中读取数据
    • 等待/死亡

看不出你为什么要执行一个新进程。如果确实需要,您必须使用标准标准输入/标准输出(参见其他答案)或有一个程序接受 fd(文件描述符,整数)作为参数,以便知道哪个是管道。我觉得不太好。

【讨论】:

    【解决方案3】:

    实际上使用自动管理通信渠道的popen 更容易做到这一点

    FILE *popen(const char *command, const char *mode); popen() 函数应执行字符串指定的命令 命令。它应该在调用程序和调用程序之间创建一个管道 执行的命令,并应返回一个指向流的指针,该流可以是 用于读取或写入管道。

    执行命令的环境应该是一个子进程 是在 popen() 调用中使用 fork() 函数创建的,并且 孩子使用以下调用调用了 sh 实用程序:

    execl(shell path, "sh", "-c", command, (char *)0);

    其中 shell path 是 sh 实用程序的未指定路径名。

    popen() 函数应确保来自先前的任何流 在父进程中保持打开的 popen() 调用在 新的子进程。

    popen() 的模式参数是一个指定 I/O 模式的字符串:

    如果mode为r,当子进程启动时,它的文件描述符 STDOUT_FILENO 应该是管道的可写端,文件 调用进程中的描述符 fileno(stream),其中 stream 是 popen() 返回的流指针,应该是 管道。

    如果 mode 是 w,当子进程启动时,它的文件描述符 STDIN_FILENO 应该是管道的可读端,文件 调用进程中的描述符 fileno(stream),其中 stream 是 popen() 返回的流指针,应该是 管道。

    如果 mode 是任何其他值,则结果未定义。

    在popen()之后,父进程和子进程都应该能够 在任一终止之前独立执行。

    管道流是面向字节的。

    返回值

    成功完成后,popen() 将返回一个指向打开的指针 可用于读取或写入管道的流。否则,它 应该返回一个空指针,并且可以设置 errno 来指示错误。

    例如假设你想给孩子发送Hello world

    #include<stdio.h>
    #include<stdlib.h>
    #include <unistd.h>
    int main()
    {
      FILE* toChild;
      toChild = popen("./child", "w");//child is executable of the other file: change the name
      int res = fputs( "Hello World\n", toChild);
      pclose(toChild);
      return 0;
    }
    

    和孩子:

    int main()
    {
      char p[100];
      int n;
      do{
        n = scanf("%s", p);
        if (n>0) {
        printf("INPUT MESSAGE: \"%s\n\"", p);
        //free(p);
        }
        else {
          printf( "%d, No matching characters\n", n);
        }
      }while(n>0);
      return 0;
    }
    

    如果您使用的是纯 POSIX 系统(而不是 OSX),您还可以使用 scanf("%ms", &amp;p)char* p,然后使用 free(p)

    【讨论】:

      猜你喜欢
      • 2014-06-09
      • 1970-01-01
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多