C:dup2,管道和fork没有按预期工作
我正在尝试做一个简单的fork – >执行另一个程序 – >对那个子进程说“你好” – >回读一些东西 – >打印收到的东西。
作为孩子使用的程序只是等待任何输入行,并向stdout打印一些东西,比如“你好!”
这是我的“主机”程序(不起作用):
#include #include #include #define IN 0 #define OUT 1 #define CHILD 0 main () { pid_t pid; int pipefd[2]; FILE* output; char buf[256]; pipe(pipefd); pid = fork(); if (pid == CHILD) { printf("child\n"); dup2(pipefd[IN], IN); dup2(pipefd[OUT], OUT); execl("./test", "test", (char*) NULL); } else { sleep(1); printf("parent\n"); write(pipefd[IN], "hello!", 10); // write message to the process read(pipefd[OUT], buf, sizeof(buf)); printf("received: %s\n", buf); } }
我明白了:
child [.. waits 1 second ..] parent received:
我错过了什么? 谢谢!
编辑(test.c):
根据要求,这是儿童计划:
#include #include #include int getln(char line[]) { int nch = 0; int c; while((c = getchar()) != EOF) { if(c == '\n') break; line[nch] = c; nch++; } if(c == EOF && nch == 0) return EOF; return nch; } main() { char line[20]; getln(line); printf("hello there!", line); fflush(stdout); return 0; }
您总是假设从文件描述符0
读取,并使用管道写入文件描述符1
…您在父进程中将此关系反转。 对于您想要做的事情,您可能最终需要两个管道用于父和子之间的双向通信,这避免了父母最终读取它写入管道的内容的情况,因为进程调度是不确定的(即,如果父节点也从同一个管道读取,则不保证子节点读取父节点写入管道的内容,因为父节点可能最终写入然后读取而没有交错子节点进程读取父节点写)。
将您的代码更改为以下内容:
main () { pid_t pid; int pipe_to_child[2]; int pipe_from_child[2]; FILE* output; char buf[256]; pipe(pipe_to_child); pipe(pipe_from_child); pid = fork(); if (pid == CHILD) { printf("child\n"); //child process not using these ends of the pipe, so close them close(pipe_to_child[1]); close(pipe_from_child[0]); dup2(pipe_to_child[0], fileno(stdin)); dup2(pipe_from_child[1], fileno(stdout)); execl("./test", "test", (char*) NULL); } else { sleep(1); printf("parent\n"); write(pipe_to_child[1], "hello!\n", 10); // write message to the process read(pipe_from_child[0], buf, sizeof(buf)); printf("received: %s\n", buf); } }
你需要两个管道:一个用于子进程的stdin,另一个用于stdout。 您不能将管道的两端重新用作两个管道。
此外,这一行的父程序
write(pipefd[IN], "hello!", 10); // write message to the process
不写新行,所以孩子的getln
永远不会返回。 (此外,“你好!”只有六个字符,但你写的是十个。)
您可能应该使用wait
或waitpid
。
看起来你的管道描述符已经混淆了。 在调用pipe()
, pipefd[0]
是管道的读取端, pipefd[1]
是管道的写入端。 您正在写入读取端,并从写入端读取。
此外,您正在尝试将一个管道用于子进程的stdin和stdout。 我不认为这是你想要做的(你需要两个管道)。
看起来管道的IN / OUT向后 – pipefd[0]
是管道的读取端,所以写入它(如父管所做的那样)是没有意义的并且会失败。 类似地, pipefd[1]
是写端,因此从它读取(如父节点那样)也将失败。 您应该始终检查读取和写入调用的返回值,以查看是否出现任何错误
其他人说管道是单向的,这是我最初想到的。 但实际上,这不是我的手册页所说的:
A read from fildes[0] accesses the data written to fildes[1] on a first-in-first-out (FIFO) basis and a read from fildes[1] accesses the data written to fildes[0] also on a FIFO basis.
但是,这确实意味着如果父级正在写入pipefd[0]
,那么子级应该从pipefd[1]
读取,因此您将管道的错误侧与子级的stdin和stdout相关联。
在手册页中,您似乎可以使用一个管道来完成此操作。 但使用两个代码可能更清晰。
看起来你正在考虑将pipefd
的每个元素作为一个单独的管道,但事实并非如此。