C – 通过管道传递管道

我正在为学校做一个项目,我不确定我试图解决它的方式是否可行。 该项目涉及制作一个程序,分离2个孩子,然后必须用其他程序替换他们的pid,并让2个孩子通过使用read()和write()通过管道进行交谈。

我的问题是使用execve并将管道传递给那个孩子。 我现在拥有的是:

家长计划 – 分叉和让孩子打电话:

#include  #include  #include  #include  #include  #include  #define BUF_SIZE 16 /* 2 cmd line arguments 1. file already in system (to be copied) 2. file to be created (the copy) create pipe (for communication) + 2 child processes first child replace pid with reader second child with writer wait for both children to terminate before exiting */ int main(int argc, char* argv[]){ //making the pipe int pfd[2]; pipe(pfd); int num_dead; //forking pid_t reader_child_pid; pid_t writer_child_pid; pid_t child_pid; //args for each fork char *args_1[] = {argv[1], (char *) 0}; char *args_2[] = {argv[2], (char *) 0}; switch(writer_child_pid = fork()) { case -1: perror("fork failed"); return 1; case 0: close(pfd[1]); dup2(pfd[0], 0); execve("./writer", args_2, NULL); perror("execve failed"); break; default: switch(reader_child_pid = fork()) { case -1: perror("2nd fork failed"); return 1; case 0: close(pfd[0]); dup2(pfd[1], 1); execve("./reader", args_1, NULL); perror("execve failed"); break; default: //close(pfd[0]); //close(pfd[1]); break; } } num_dead = 0; for(;;) { if((child_pid=wait(NULL)) == -1){ if(errno == ECHILD) { printf("NO MORE CHILDREN"); exit(0); } else { perror("wait error"); exit(1); } } ++num_dead; printf("wait() returned 1 child"); } } 

尝试使用dup2重定向到stdin和stdout。 然后在孩子们中我尝试读取和写入stdout和stdin,如下所示:

孩子 – 从stdin读取数据

 #include  #include  #include  #include  #include  #define BUF_SIZE 16 int main(int argc, char* argv[]){ printf("\n\nWRITER\n"); /* ready to process info read the file, write it to pipe */ int wri_inFile = open(argv[0], O_WRONLY | O_CREAT | O_TRUNC | S_IRUSR | S_IWUSR); char buf[BUF_SIZE]; int read_test; for(;;) { read_test = read(0, buf, BUF_SIZE); if(read_test == 0) //eof break; write(wri_inFile, buf, BUF_SIZE); } close(wri_inFile); exit(0); } 

我根据你的建议使用dup,但我不确定我是否正在按照我应该的方式访问stdin和stdout。

– 这是另一个孩子仅供参考

 #include  #include  #include  #include  #include  #define BUF_SIZE 16 int main(int argc, char* argv[]){ printf("\n\nREADER\n"); /* ready to process info read the file, write it to pipe */ printf("FILE::%s", argv[0]); int inFile = open(argv[0], O_RDONLY); char buf[BUF_SIZE]; int read_test; for(;;) { read_test = read(inFile, buf, BUF_SIZE); if(read_test == 0) //eof break; write(1, buf, BUF_SIZE); } close(argv[0][1]); close(inFile); printf("\nDONE WITH READER\n"); exit(0); } 

– 如果它有任何区别,它似乎是另一个孩子(写入管道的那个)成功写入它,但上面的孩子从不从管道读取,并且从上面的outFile总是为空。

* *仍然发生同样的事情

我不是在找你为我解决问题,我只是真的陷入困境,不知道我是否做了一些非常错误的事情。 再次感谢您的帮助。

我正在积极寻找可以使用的示例,但我找不到任何显示来自孩子的代码,他们执行的代码现在是我的问题所在。

使用管道时,必须确保过程不会保持管道打开(除非过程实际使用管道)。 特别是,在此上下文中,父进程必须关闭管道的两端,否则读者将永远不会获得EOF指示。

在仔细阅读其他两个程序之后,我看到阅读器程序读取它所给出的文件并将该内容写入管道,并且编写器程序将给出的文件写入它从管道读取的数据。

此代码是关于将起作用的最小更改:

 #include  #include  #include  #include  /* 2 cmd line arguments 1. file already in system (to be copied) 2. file to be created (the copy) create pipe (for communication) + 2 child processes first child replace pid with reader second child with writer wait for both children to terminate before exiting */ int main(int argc, char* argv[]) { //making the pipe int pfd[2]; pipe(pfd); // Error check omitted! int num_dead; //forking pid_t reader_child_pid; pid_t writer_child_pid; pid_t child_pid; if (argc != 3) { fprintf(stderr, "Usage: %s infile outfile\n", argv[0]); return 1; } //args for each fork char *args_1[] = { "reader", argv[1], (char *) 0 }; char *args_2[] = { "writer", argv[2], (char *) 0 }; switch (writer_child_pid = fork()) { case -1: perror("fork failed"); return 1; case 0: // writer reads from standard input (pipe) and writes to named file dup2(pfd[0], 0); // Error check omitted close(pfd[0]); close(pfd[1]); execve("./writer", args_2, NULL); perror("execve failed"); return 1; default: switch (reader_child_pid = fork()) { case -1: perror("2nd fork failed"); return 1; case 0: //reader reads from the named file and writes to the pipe dup2(pfd[1], 1); close(pfd[0]); close(pfd[1]); execve("./reader", args_1, NULL); perror("execve failed"); return 1; default: // The parent closes both ends of the pipe close(pfd[0]); close(pfd[1]); break; } } num_dead = 0; for(;;) { if ((child_pid = wait(NULL)) == -1){ if (errno == ECHILD) { printf("NO MORE CHILDREN\n"); exit(0); } else { perror("wait error"); exit(1); } } ++num_dead; printf("wait() returned 1 child (%d)\n", (int)child_pid); } return(0); } 

请注意,每个子节点和父节点在完成其工作之前都会关闭管道文件描述符。

我可能不会使用嵌套开关来控制流,我可能会使用函数来处理每个子进程的处理:

 if ((child1 = fork()) == -1) ...error... else if (child1 == 0) launch_reader(pfd, args_1); else if ((child2 = fork()) == -1) ...error... else if (child2 == 0) launch_writer(pfd, args_2); ...parent... 

我也有一个函数来封装’报告错误并退出’,即使它只有两行长。 此外,如果您确实希望它们及时显示,请确保来自printf()消息以换行符结尾。

我在下面标出了问题。

 switch(reader_child_pid = fork()) { // ... default: close(pfd[1]); // <-------------------- close(pfd[0]); switch(writer_child_pid = fork()) { // ... default: break; } } 

在这里,在分叉第二个子节点之前,关闭父节点中管道的两端。 因此,两端也在第二子进程中关闭。 您应该将这些关闭语句移动到第二个default块,以便在第二个子项分叉后关闭它们。

 switch(reader_child_pid = fork()) { // ... default: switch(writer_child_pid = fork()) { // ... default: close(pfd[1]); close(pfd[0]); break; } }