我试图创建一个运行任何给定Linux命令的程序,直到用户输入"停止"。
父亲应该生一个孩子,这个孩子也应该生孩子。
所以,让我们说A是父亲,B是儿子,C是孙子。
A - >从用户输入中读取命令 并将其发送到B
B - >从管道中读取命令 并将其发送到C
C - >从管道中读取命令 并使用execl
。输出应发送到发送到B的管道,然后B将输出显示到屏幕。
所以我将有3个管道:1个从A到B,1个从B到C,1个从C到B。
管道p1:A到B
管道p2:B到C
管道p3:C到B
这是我的代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int p1[2], p2[2],p3[3];
pipe(p1);
pipe(p2);
pipe(p3);
char cmd[20],buffer[128];
while(1<2)
{
printf("Type a cmd: \n");
scanf("%s20",cmd);
if(strcmp(cmd,"stop")==0)
{
break;
}
else
{
close(p3[1]);
close(p3[0]);
close(p1[0]);
close(p2[1]);
close(p2[0]);
write(p1[1],&cmd,sizeof(char)*20);
if(fork()==0)
{
close(p1[1]);
close(p2[0]);
close(p3[1]);
read(p1[0],&cmd,sizeof(char)*20);
write(p2[1],&cmd,sizeof(char)*20);
if(fork()==0)
{
close(p1[0]);
close(p1[1]);
close(p2[1]);
close(p3[0]);
read(p2[0],&cmd,sizeof(char)*20);
char bin[20]="/bin/";
strcat(bin,cmd);
dup2(p3[1],1);
execl(bin,bin,NULL);
exit(1);
}
wait(0);
dup2(p3[0],0);
while(read(p3[0],&buffer,sizeof(char)))
{
printf("%s",buffer);
}
exit(1);
}
}
wait(0);
}
return 0;
}
我认为我错误地使用close()
因为我不确切地理解它的作用。使用AFAIK是因为每次使用fork()
时,FD都会重复使用。
到目前为止,它确实编译并运行,但如果我输入&#34; ls&#34;,程序将终止。
如果我删除了对close()
的所有电话,&#34; ls&#34;会工作,但它会阻止,不允许我输入第二个命令。
答案 0 :(得分:3)
您的程序会创建三个管道,然后在调用p2
之前完全关闭其中两个管道(p3
和fork()
)。它还会同时关闭p1
的读取结束。您的子进程将无法获得任何可用的文件句柄。
pipe(p1);
pipe(p2);
pipe(p3);
char cmd[20],buffer[128];
while(1<2) {
...
else {
close(p3[1]);
close(p3[0]);
close(p1[0]);
close(p2[1]);
close(p2[0]);
...
write(p1[1],&cmd,sizeof(char)*20);
在fork
之后,孩子关闭单个剩余的管道文件句柄(这确实不是问题),然后尝试从已经由父项关闭的文件句柄中读取:
if(fork()==0) {
...
close(p1[1]);
...
read(p1[0],&cmd,sizeof(char)*20);
通常,你首先需要fork
,然后关闭不需要的文件句柄,即对于父对子通信,只有父对象应该关闭读取结束,只有子对象应该关闭写入端。
当然,如果父级关闭了管道的一端,那么在循环的 next 迭代中,该文件句柄将无法用于新的子进程,因此您需要在那时创建一个新的pipe
。或者保持所有fd在主程序中打开(但我不记得是否会导致管道问题)。
至于你从孩子到孙子的fd,你需要在做fork
时以同样的方式对待他们。虽然我建议先做一个双过程实验。