需要帮助命名管道和popen

时间:2010-07-27 17:41:35

标签: c pipe popen

我有一个小C服务器需要接受连接并分叉子进程。我需要将子进程的stderr转到已存在的命名管道,将stdout转到父级的stdout,然后stdin孩子tp的来源与父母的stdin相同。

我最初的尝试涉及popen(),但我似乎永远无法得到我想要的东西。

最后,这个特定的解决方案只需要在Solaris中运行。感谢。

编辑:更新了问题,希望能更准确地描绘我想要完成的任务。谢谢你对我有耐心。

EDIT2:我还需要父进程来获取子进程的返回值,然后对它做一些事情,如果这有任何区别。

1 个答案:

答案 0 :(得分:5)

您可能使用了错误的函数 - 当您希望调用程序写入分叉进程的标准输入或从其标准输出读取时,使用popen()。看来你也不想要。它还需要两个参数。

您的要求也有些矛盾:

  • 我希望它(理想情况下)从父母继承stdin和stdout

  • 父母的任何输入都会转到子级,而子级的任何输出都会返回到父级

  • 但至少,我希望它继承stdin并将stdout写入命名管道

第一个选项很简单 - 它不需要特殊编码。提供给父级的stdin的任何数据也将在子级的stdin上可用(但只有两个进程中的一个将读取它)。孩子的stdout通常会和父母的stdout去同一个地方。如果你想让父母读取孩子的标准输出,那么你确实需要一个管道 - 然后popen()是合适的,但是“至少”的东西是令人困惑的。

那么,让我们定义你真正想要的东西吗?

选项1

  1. 孩子的标准错误应该转到命名管道。
  2. 应该通过调用过程读取子项的标准输出。
  3. 孩子的标准输入应来自父母的标准输入。
  4. 命名管道已存在。
  5. 因此:

    FILE *fp = popen("/run/my/command -with arguments 2>/my/other/pipe", "r");
    

    请注意,子进程将挂起,直到进程打开'/ my / other / pipe'进行读取;这反过来意味着如果父进程从fp读取,它也将被挂起,直到其他进程打开'/ my / other / pipe'进行读取。

    选项2

    1. 孩子的标准错误应该转到命名管道。
    2. 孩子的标准输出应该转到父母的标准输出。
    3. 孩子的标准输入应来自父母的标准输入。
    4. 命名管道已存在。
    5. 现在popen()不合适,我们进入赤裸的`fork&执行代码。接下来是比操作C更多的伪代码。

      if ((pid = fork() < 0)
          error
      else if (pid > 0)
      {
          /* Parent - might wait for child to complete */
      }
      else
      {
          int fd = open("/my/other/pipe", O_WRONLY|O_NONBLOCK);
          if (fd < 0)
              error
          dup2(fd, 2);  /* There is a symbolic name for stderr too */
          close(fd);    /* Do not want this open any more */
          char *cmd[4] = { "/bin/sh", "-c", "/run/my/command -with arguments", 0 };
          execv(cmd[0], cmd);
          error - if execv returns, it failed!
      }
      

      如果你完全有信心没有人像你关闭stdout那样对你施加任何特技,你可以通过在调用dup2()之前关闭stderr(fd = 2)来避免使用open()。但是,如果您这样做,则无法再报告任何错误 - 因为您关闭了stderr。所以,我会这样做。

      如果您有不同的要求,请说明您想要达到的目标。


      如p2vb所述,如果您希望父母等待孩子完成,那么仅使用system()就足够了。如果父级应该在子级运行时继续,则可以尝试system(),其中命令字符串以&符号(&)结束以将子项置于后台,或者您可以使用上面的备选方案2。

      使用system(),父母几乎没有机会阅读/ my / other / pipe,它会从孩子那里获得标准错误。如果孩子经常生产,你很容易陷入僵局。

      另外,请注意FD_CLOEXEC标志 - 将其设置在您不希望子项修改的文件上。在Linux上,您可以在open()调用上使用O_CLOEXEC标志;对于Solaris,您必须通过fcntl() - 仔细设置它。