C 调用popen后如何在父进程和子进程之间使用管道?
我希望与子进程通信,如下所示:C 调用popen后如何在父进程和子进程之间使用管道?,c,pipe,parent-child,ipc,interprocess,C,Pipe,Parent Child,Ipc,Interprocess,我希望与子进程通信,如下所示: 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);
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;
}
程序正在运行,即sendto的接收器将接收数据
我尝试像在子进程中那样使用管道:
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);
}
}
但与此不发送
那么,在这种情况下,如何使用管道来实现与第一种情况相同的行为呢?我是否应该执行dup2STDIN_FILENO,fd[0];或者dup2STDOUT_FILENO,fd[0]
我使用的是sandards,因为文件描述符是由子进程继承的,所以不需要任何其他工作。这就是为什么我认为我可以使用管道,但事实是这样吗?手动设置管道的常用方法是,父进程可以从中读取子进程的标准输出,其一般步骤如下: 父对象通过调用管道来创建管道 母叉 父对象:其管道写入端的副本 子级通过dup2将管道的写入端复制到其标准输出上 child关闭管道写入端的原始文件描述符 可选子对象:其管道读取端的副本 child执行所需的命令,或者直接执行所需的工作 然后,父对象可以从管道的读取端读取子对象的输出 popen函数可以为您完成所有这些,并将父级的管道端点包装到一个文件中。当然,如果调用者要求相反的方向,它可以也将设置一个管道 您需要理解并理解,在上述程序方案中,重要的是哪些操作由哪个流程执行,以及与同一流程中的其他操作相关的顺序。特别是,在启动子管道之前,父管道不能关闭管道的写入端,因为这样会使管道变得无用。子对象继承一端封闭的管道,通过该管道无法传输任何数据 关于后一个示例,还要注意,将标准输入重定向到管道的读取端不是父级或子级处理的一部分。事实上,你的管道是半封闭的,因此无论如何都无法从中读取任何内容,这只是锦上添花。此外,父级以这种方式重击自己的标准输入。这并不一定是错的,但父母甚至都不依赖它 然而,总的来说,有一个更大的图景你似乎并不欣赏。即使您在父级中执行了您似乎想要的重定向,以便子级可以继承它,popen也会执行它自己的重定向到它自己创建的管道。它返回的文件*是您可以读取子对象输出的方法。您以前可能执行的输出重定向与子级标准输出的澄清无关 原则上,可以使用类似于您的方法来创建另一个方向的第二个重定向,但在这一点上,popen的便利性因素完全丧失了。如果要重定向子级的输入和输出,最好一直使用directpipe/fork/dup2/exec路由 将所有这些应用到第一个示例中,您必须了解,尽管流程可以重定向其自己的标准流,但它不能以这种方式建立到其父流程的管道。父级需要提供管道,否则它不知道该管道。当一个进程将一个文件描述符复制到另一个文件描述符上时,会用新的替换原始文件,如果原始文件已打开,则会关闭它。它不会重新定义原始的。当然,在这种情况下,如果管道的任意一端不再在任何地方打开,管道也就没有用了。在父管道中:
if (pipe(fd) < 0)
{
// pipe error
exit(1);
}
close(fd[0]);
你得到一根管子,然后立即关闭它的一端。这条管道现在毫无用处,因为没有人能够恢复封闭端,因此没有数据可以通过它。您已将管道转换为一端密封的空心圆柱体
然后在孩子身上:
if (pipe(fd) < 0)
{
// pipe error
exit(1);
}
close(fd[1]);
创建另一个不相关的管道,并在另一端密封该管道。这两条管道没有连接,现在有两个单独的空心自行车,每一个都在一端密封。任何东西都不能通过它们
如果把东西放在第一个圆筒里,让它出现在另一个圆筒里,那将是一个相当好的魔术。如果不耍花招或巧妙地安排镜像,解决方案是创建一个管道,保持两端打开,并将数据推送到其中。我不明白您在这里想要实现什么。popen的要点是允许您避免直接管理管道和文件描述符。如果您想要更大的灵活性或不同的界面,那么您可以始终以通常的方式手动执行管道管理和fork/exec。但是把两者混合起来对你有什么好处呢?是的,我知道,我在问题中也说过波本是有效的,但我想了解为什么管道的另一种方式不起作用。这就是我想要达到的目标。顺便说一句,还有很多
这里的代码与管道问题毫无关系,除了看到两个管道的问题外,我真的不知道您想要实现什么。您的两个孩子的样本也使用popen,这有点让人困惑,我不知道您所说的“未发送”的具体含义。什么没有被发送,在哪里,你是怎么说的,你期望被发送什么?为什么是否决票?所以基本上,如果我理解正确,子进程中的fd是错误的。那么我应该传递哪个文件描述符来写呢?你是说在第一个代码中,@FrancescoBoi?在这种情况下,如果父级通过popen启动子级,就像在第二个代码中一样,那么子级只会写入其标准输出。它根本不需要知道重定向。这就是重定向的全部要点,尤其是popen执行的重定向。如果它依赖于子进程做一些特殊的事情,那么它的用处就会小得多。在exec之后做一些特殊的事情,也就是说。那么当我在子进程中写入时,我应该使用什么?您只能写入fd[1]并从fd[0]读取。父对象具有两端,子对象继承两端。这取决于你选择如何使用它们。我真的不知道您想要在父进程和子进程之间交流什么,也不知道您想要实现什么,因此我无法就如何实现它向您提供建议。NB。显示了一个在类似情况下使用socketpair的简单示例-这将允许双向消息,但编写的代码与管道的工作方式相同。另一个疑问是,您说这些管道是不相关的,但我复制了这些管道中的标准输出,因此我以某种方式使它们相关:不是这样吗?我不否认它们可能完全无用,因为此时我可以直接写入std输出。你调用管道两次,就会得到两个不同的管道。说他们有亲戚关系是因为你把一个的一端复制到了stdout上,另一个的另一端复制到了stdin上,就像说两个人有亲戚关系是因为他们坐在同一辆车上。
if (pipe(fd) < 0)
{
// pipe error
exit(1);
}
close(fd[1]);