C – Передача трубы через execve

Я работаю над проектом для школы, и я не уверен, возможно ли то, как я пытаюсь его решить. Проект включает в себя создание программы, форсирование двух детей, которые затем должны заменить их 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); } 

Обратите внимание, что каждый ребенок и родитель закрывают оба дескриптора файла pipe до завершения их работы.

Я бы, вероятно, не использовал вложенные ключи для streamа управления, и я бы, вероятно, использовал функции для обработки обработки каждого дочернего элемента:

 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; } }