我正在为一所学校的项目工作,我不确定我试图解决它的方式是否可行。该项目涉及制作一个程序,分离2个孩子,然后必须用其他程序替换他们的pid,并让2个孩子通过使用read()和write()通过管道进行交谈。
我的问题是使用execve并将管道传递给那个孩子。我现在拥有的是:
家长计划 - 分叉并让孩子打电话给他们:
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#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 <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#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 <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#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总是为空。 / p>
* *仍然发生同样的事情
我不是在找你为我解决问题,我真的被困住了,不知道我做错了什么。再次感谢您的帮助。
我正在积极寻找可以使用的示例,但我找不到任何显示他们执行的代码的代码,这是我现在的问题所在。
答案 0 :(得分:4)
使用管道时,必须确保过程不会保持管道打开(除非过程实际使用管道)。特别是,在此上下文中,父进程必须关闭管道的两端,否则读者将永远不会获得EOF指示。
在仔细阅读其他两个程序之后,我看到阅读器程序读取它所给出的文件并将该内容写入管道,并且编写器程序将给出的文件与它从中读取的数据一起写入管道。
此代码是关于可行的最小更改:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
/* 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()
的邮件以换行符结尾。
答案 1 :(得分:1)
我在下面标出了问题。
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;
}
}