我有一个小C服务器需要接受连接并分叉子进程.我需要的stderr子进程的去一个已经存在的命名管道,将stdout孩子转到stdout父,和stdin孩子的TP来自同一个地方作为stdin母公司.
我最初的尝试涉及popen()但我似乎永远不会得到我想要的.
最后,这个特定的解决方案只需要在Solaris中工作.谢谢.
编辑:更新了问题,希望能更准确地描绘我想要完成的事情.谢谢你对我耐心.
EDIT2:我还需要父进程获取子进程的返回值,然后对它做一些事情,如果这有任何区别.
您可能正在使用错误的函数 - popen()当您希望调用程序写入分叉进程的标准输入或从其标准输出读取时使用.看来你也不想要.它还需要两个参数.
您的要求也有些矛盾:
我希望它(理想情况下)从父级继承stdin和stdout
父进程的任何输入都传递给子进程,子进程的任何输出都返回到父进程
但至少,我希望它继承stdin并将stdout写入命名管道
第一个选项很简单 - 它不需要特殊编码.提供给父级的stdin的任何数据也将在子级的stdin上可用(但只有两个进程中的一个将读取它).孩子的stdout通常会和父母的stdout去同一个地方.如果你想让父母读取孩子的标准输出,那么你确实需要一个管道 - 然后popen()是合适的,但是"至少"的东西是令人困惑的.
那么,让我们来定义你真正想要的东西?
因此:
FILE *fp = popen("/run/my/command -with arguments 2>/my/other/pipe", "r");
Run Code Online (Sandbox Code Playgroud)
请注意,子进程将挂起,直到进程打开'/ my/other/pipe'进行读取; 这反过来意味着如果父进程读取fp,它也将被挂起,直到其他进程打开'/ my/other/pipe'进行读取.
现在popen()不合适,我们进入裸`fork&exec'代码.接下来是比操作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!
}
Run Code Online (Sandbox Code Playgroud)
如果你完全有信心没有人像关闭stdout一样对你施加任何特技,你可以避免dup2()在打电话之前关闭stderr(fd = 2)open().但是,如果您这样做,则无法再报告任何错误 - 因为您关闭了stderr.所以,我会如图所示这样做.
如果您有不同的要求,请说明您想要达到的目标.
如p2vb所述,如果您希望父母等待孩子完成,那么仅仅使用system()就足够了.如果父节点在子节点运行时应该继续,您可以尝试system()在命令字符串以&符号(&)结束的位置将子节点放入后台,或者您可以使用上面选项2中概述的代码.
使用时system(),父母几乎没有机会阅读/ my/other/pipe,它会从孩子那里获得标准错误.如果孩子产生很多,你很容易陷入僵局.
另外,请注意FD_CLOEXEC标志 - 将其设置在您不希望子项修改的文件上.在Linux上,您可以在open()呼叫中使用O_CLOEXEC标志; 对于Solaris,您必须fcntl()仔细设置它.