我正在写一个由父母和他的孩子(使用fork)组成的C程序。他们通过管道交流。 Parent通过标准输出写入管道,子项通过标准输入从管道读取。一旦他们连接,父母写道"你好世界"进入管道,儿子叫exec。我的代码如下所示:
int main(int argc, char *argv[])
{
int p, a;
char buf[1024];
FILE *file;
size_t nread;
int fd[2];
char argument[PATH_MAX];
if(pipe(fd)<0){
return 1;
}
p = fork();
switch(p){
case -1: perror("Error en el fork()"); return 1;
case 0:
close(fd[1]);
close (0);
dup(fd[0]);
close(fd[0]);
sprintf(argument,"/usr/bin/%s",argv[1]);
execvp(argument,argv);
perror("Error en el execv");
exit(1);
default: break;
}
close(fd[0]);
close(1);
a = dup(fd[1]);
close(fd[1]);
write(1,"Hello World\n",12);
close(a);
wait(NULL);
return 0;
}
由子执行的exec函数调用函数rev或wc。如果不带参数调用,则应将rev和wc应用于标准输入(&#34; hello world&#34;在我的情况下)。但这不起作用,我不知道为什么。任何帮助都会非常感激。
答案 0 :(得分:2)
这不起作用,我不知道为什么
因为您使用的是dup()
。要将子进程的标准输入重定向到管道,要使用的正确系统调用是dup2()
case 0:
close( fd[1] );
dup2( fd[0], 0 ); // this "dup"s the read-end of the pipe onto STDIN
close( fd[0] );
请注意,父代码分支中根本不需要dup()
调用。只需写入管道的写端:
write( fd[1], "Hello World\n", 12 );
但是,如果你想在父分支中使用execvp,要启动另一个程序并重定向其标准输出,那么你也必须在这里使用dup2()
:
dup2( fd[1], 1 ); // this "dup"s the write-end of the pipe onto STDOUT
close( fd[1] );
阅读dup2
的{{3}}了解详情。
此外,您的代码的另一个问题是使用带有argv
的execvp作为参数列表。这将导致rev
和wc
等程序接收父程序的整个命令行,从而找到一个参数来处理而不是从标准输入读取。你可能想要
execvp( argv[1], &argv[1] );
答案 1 :(得分:1)
您在以下代码中错误地使用execvp()
:
sprintf(argument,"/usr/bin/%s",argv[1]);
execvp(argument,argv);
如果您按./a.out wc
运行程序,那么在这种情况下,/usr/bin/wc
的参数将为./a.out wc
,即原始参数列表为./a.out
,然后{{ 1}}将尝试在当前工作目录中打开名为/usr/bin/wc
的文件,而不是从标准输入中读取。
所以将上面的代码更改为
wc
应该解决问题,这次 sprintf(argument,"/usr/bin/%s",argv[1]);
execvp(argument,NULL);
的参数列表将是一个空列表。