我正在尝试制作一个程序来运行任何给定的 Linux 命令,直到用户输入“停止”为止。
父亲要生 child ,父亲也要生 child 。
假设 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 都是重复的。
到目前为止,它确实可以编译和运行,但是如果我输入“ls”,程序就会终止。
如果我删除对 close()
的所有调用,“ls”将起作用,但它会阻塞,不允许我输入第二个命令。
最佳答案
您的程序创建三个管道,然后在调用 fork()
之前完全关闭其中两个(p2
和 p3
)。它还同时关闭了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
,然后关闭不需要的文件句柄,即对于父子通信,只有父应该关闭读取端,只有子应该关闭写端。
当然,如果父进程关闭了管道的一端,那么在循环的下 迭代中,新的子进程将无法使用该文件句柄,因此您需要在该点创建一个新的 pipe
。或者在主程序中保持所有 fd 处于打开状态(但我不记得这是否会导致管道出现问题)。
至于从子代传给孙代的 fd,您需要在执行该fork
时以相同的方式对待它们。尽管我建议先进行双过程实验。
关于c - 我错误地使用了 close() 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43878248/