【发布时间】:2018-12-03 00:33:38
【问题描述】:
我正在尝试通过 C 中的标准输入和标准输出的管道重定向与分叉的子进程通信。我已经设法让它适用于在子进程中执行的 shell 命令(例如ls)。但是,我无法通过从子进程到父进程的管道递归执行相同的程序并重定向输出(由printf()、fprintf() 打印到stdout,...)(在此测试中)到父级的stdout),尽管这适用于ls 或类似的命令。
这是我尝试解决此问题的方法:
- 我创建了一个管道,读端是给父进程的,子进程应该写到写端。
- 进程分叉,两个进程分别关闭未使用的端。
- 管道的写入端重定向到
STDOUT_FILENO并关闭 - 子进程递归执行程序(称为./to2)
如前所述,如果我在子进程中执行ls,这确实有效,但如果我尝试递归调用同一个程序,则不会。这是我试图让它工作的测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <netdb.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
static void usage(void){
fprintf(stderr,"RIP");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]){
if(argc > 1){
dprintf(STDOUT_FILENO,"Please work\n");
printf("\n THIS IS A MESSAGE FROM THE CHILD \n");
fputs("Pretty Please!\n",stdout);
fflush(stdout);
exit(EXIT_SUCCESS);
}
int p1[2];
if(-1 == pipe(p1)) {
fprintf(stderr,"pipe\n");
fprintf(stderr,"%s\n",strerror(errno));
usage();
}
int f = fork();
if(f == 0){
close(p1[0]);
if(dup2(p1[1],STDOUT_FILENO) < 0){
fprintf(stderr,"dup2\n");
usage();
}
close(p1[1]);
//I want this to work:
//execlp("./to2", "./to2", "-e");
//This works fine:
execlp("ls", "ls");
exit(EXIT_SUCCESS);
} else if (f == -1) {
usage();
} else {
close(p1[1]);
int w = -1;
if(-1 == wait(&w)) usage();
char b[12];
memset(b,0,12);
read(p1[0],&b,12);
char reading_buf[1];
while(read(p1[0], reading_buf, 1) > 0){
write(1, reading_buf, STDOUT_FILENO);
}
close(p1[0]);
}
}
出于测试目的,该函数是使用附加参数递归调用的,而父程序是在没有附加参数的情况下调用的(因此if(argc>1))。
在最终的程序中,通过其他方式避免了无限递归。
我理解错了吗?我很困惑,唯一似乎不起作用的是重定向我的 own 的输出 程序...
非常感谢您,非常感谢您提供任何帮助或想法。
【问题讨论】:
-
欢迎来到 Stack Overflow。请尽快阅读About 和How to Ask 页面。当您向我们展示代码时,您应该旨在展示一个 MCVE (minimal reproducible example)。你的代码中有相当多的头文件没有被使用——
<signal.h>、<sys/netdb.h>、<sys/socket.h>、<time.h>、<fcntl.h>、<sys/stat.h>我相信没有使用,而<sys/types.h>没有使用在现代 POSIX(自 2004 年以来,IIRC)中并不真正需要,尽管 Linux 手册页仍然倾向于列出它。请确保您的错误消息以换行符结尾;它提高了可读性。当execlp()失败时,使用EXIT_SUCCESS退出是不常见的。 -
你说的是递归,但这里只显示了两个函数——
main()和usage()。我看不到对main()和usage()的递归调用肯定不是递归的,所以不清楚你的意思。 -
您说
//This works fine:后跟一个损坏的execlp("ls", "ls");- 这应该不起作用,因为您没有提供空指针来标记参数列表的结尾(execlp("ls", "ls", (char *)0);是正确的) .它可能碰巧起作用,但它肯定是不正确的。您是正确的,您不需要测试来自execlp()的返回值——它永远不会在成功时返回,只会在执行指定的子程序失败时返回。 -
空指针丢失很可能是您在编写程序以再次运行时遇到问题的原因。但是,这不是“递归”通常的含义。通常,递归是指在单个进程中直接或间接调用自身的函数。
标签: c recursion pipe fork io-redirection