如何父母和孩子之间的过程使用管道调用之后popen方法?

问题描述 投票:-1回答:2

我想类似下面的子进程进行通信:

int main(int argc, char *argv[])
{
    int bak, temp;
    int fd[2];
    if (pipe(fd) < 0)
    {
        // pipe error
        exit(1);
    }
    close(fd[0]);
    dup2(STDOUT_FILENO, fd[1]);
    fflush(stdout);
    bak = dup(1);
    temp = open("/dev/null", O_WRONLY);
    dup2(temp, 1);
    close(temp  );
    Mat frame;
    std::vector<uchar> buf;
    namedWindow( "Camera", WINDOW_AUTOSIZE );
    VideoCapture cam(0 + CAP_V4L);
    sleep(1);
    if (!cam.isOpened())
    {
        cout << "\nCould not open reference " << 0 << endl;
        return -1;
    }
    for (int i=0; i<30; i++)
    {
        cam>>frame;
    }
    //cout<<"\nCamera initialized\n";
    /*Set the normal STDOUT back*/
    fflush(stdout);
    dup2(bak, 1);
    close(bak);

    imencode(".png",frame, buf);
    cout<<buf.size()<<endl;
    ssize_t written= 0;
    size_t s = 128;
    while (written<buf.size())
    {
     written += write(fd[1], buf.size()+written, s);

    }
    cout<<'\0';
    return 0;

}

对应于上述的源代码的编译过程中从与popen父调用。

请注意,我写的是已被复制了pipe性病出来。

父将读取数据,并将它们重新发送到UDP套接字。

如果我做这样的事情:

#define BUFLEN 128
FILE *fp;
char buf[BUFLEN];
if ((fp = popen("path/to/exec", "r")) != NULL)
{
    while((fgets(buf, BUFLEN, fp)!=NULL))
    {
        sendto(sockfd, buf, strlen(buf),0, addr, alen);
    }
}

程序的工作即sendto的接收器将接收的数据。

我试图用pipe作为子进程来完成:

    int fd[2];
    if (pipe(fd) < 0)
    {
        // pipe error
        exit(1);
    }
    close(fd[1]);
    dup2(STDIN_FILENO, fd[0]);
    if ((fp = popen("path/to/exec", "r")) != NULL)
    {
        while((read(fd[0], buf, BUFLEN) > 0)
        {
            sendto(sockfd, buf, strlen(buf),0, addr, alen);
        }
    }

但与此不发送。

因此,如何利用pipe在这种情况下,实现第一种情况相同的行为呢?我应该怎么办dup2(STDIN_FILENO, fd[0]);dup2(STDOUT_FILENO, fd[0]);

我现在用的是sandard(一个或多个),因为文件描述符由子进程继承所以应该不需要任何其他的努力。这就是为什么我认为我可以使用pipe不过是这样的吗?

c pipe parent-child ipc interprocess
2个回答
2
投票

在父:

if (pipe(fd) < 0)
{
    // pipe error
    exit(1);
}
close(fd[0]);

你会得到一个管道,然后立即关闭它的一端。这条管道是现在没有用了,因为没有人会能够恢复封闭端,因此没有数据可以流过它。你已经转换管道进入在一端密封的中空圆柱体。

然后,在孩子:

if (pipe(fd) < 0)
{
    // pipe error
    exit(1);
}
close(fd[1]);

创建另一个不相关的管道,并在另一端密封此。两个管没有连接,现在你有两个单独的中空cyclinders,在一个端部的每个密封。没有任何东西可以通过它们中的流动。

如果将东西,第一汽缸中做它出现在其他的,那将会是一种相当不错的魔术。无手或巧妙地安排镜花招,该解决方案是创建一个管,保持两端开口,并通过将其推数据。


1
投票

通常的方法手动设置的管道从父进程可以读取一个子进程的标准输出具有以下常规步骤:

  • 父母通过调用pipe()创建一个管道
  • fork()s
  • 父关闭(澄清:其复印件)管道的写入结束
  • 子愚弄管道的写入结束到经由dup2()其标准输出
  • 孩子关闭了管道的写入结束原来的文件描述符
  • (可选)子进程关闭(澄清:其复印件)管道的读端
  • 孩子高管所需的命令,否则直接进行想要的工作

然后,家长可以从管道的读端读孩子的输出。

popen()功能做了这一切给你,加上包装母公司的管端在FILE。当然,它能够而且将会建立一个管道在相反的方向,而不是如果这就是来电请求去。

你需要理解和欣赏,在上面介绍的程序方案,重要的是它的行动,进行基于该过程,相对于在同一过程中的其他动作顺序。特别是,家长一定不能关闭子推出之前管道的写入结束,因为这使管道没用。子程序继承一端封闭管,通过它没有数据可以被传送。

对于你的后一个例子中,还要注意的是标准输入重定向到管道的读到底是不是对父母任何一方或子女过程中的一部分。你管半封闭的,所以没有什么能永远地从它无论如何读的事实,只是锦上添花。此外,家长则会覆盖自己的标准输入这种方式。这不一定错,但父母甚至不依赖于它。

但总体而言,还有就是你似乎并不欣赏一个更大的图片。即使你执行你似乎想在父,以便它可以由子女继承重定向,popen()执行其自己重定向到它自己创造的一个管道。它返回的FILE *是通过它可以阅读孩子的输出手段。你可能已经执行了以前没有输出重定向是相关的(澄清:孩子的标准输出)。

原则上,类似你们的方法可以用来创建第二个重定向走另一条路,但在这一点上popen()的便利因素完全消失。如果你想重定向孩子的输入和输出可能会更好过去采取直接pipe / fork / dup2 / exec路线的所有道路。


将一切都交给你的第一个例子,你要明白,虽然过程可以重定向它自己的标准流,也无法建立一个管道,这样它的父进程。家长需要提供管道,否则它毫不知情。而当一个进程愚弄一个文件描述符到另一个,它取代了原来的新,关闭原来的,如果它是开放的。它不会重新定义原始。当然,在这种情况下,太,管也没用,一旦两端不再是开放的任何地方。

© www.soinside.com 2019 - 2024. All rights reserved.