C: dup2, pipe and plug do not work properly

I am trying to make a simple fork -> execute another program -> say hello to this child process -> read something -> print received.

The program used as a child simply waits for some input line and prints something to stdout as "hello there!"

This is my "host" program (which does not work):

#include <sys/types.h> #include <unistd.h> #include <stdio.h> #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); } } 

I get this:

 child [.. waits 1 second ..] parent received: 

What am I missing? Thanks!

EDIT (test.c):

On request, this is a child program:

 #include <stdio.h> #include <string.h> #include <stdlib.h> 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; } 
+6
source share
6 answers

You should always read from file descriptor 0 and write to file descriptor 1 using pipes ... you have this feedback in the parent process. For what you want to do, you may need two channels for two-way communication between the parent and the child, which avoids situations where the parent finishes reading the content that he wrote in the pipe, since the process planning is not deterministic (i.e. the child is not guaranteed read what the parent wrote in the pipe, if the parent also reads from the same channel, because the parent can just finish writing, and then read without interlacing the child process to read that parent Isal).

Change the code to the following:

 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); } } 
+3
source

To do this, you need two pipes: one for the stdin child process and one for its stdout. You cannot reuse the two ends of a pipe as two pipes.

In addition, this line of the parent program

 write(pipefd[IN], "hello!", 10); // write message to the process 

does not write a new line, so getln in child will never return. (Also, โ€œhello!โ€ Has only six characters, but you write ten.)

+2
source

You should probably use wait or waitpid .

+1
source

It looks like your pipe descriptors are messed up. After calling pipe() , pipefd[0] is the read end of the pipe, and pipefd[1] is the end of the pipe entry. You write until the end of the reading and read from the end of the recording.

In addition, you are trying to use one channel for stdin and stdout of a child process. I do not think that this is really what you want to do (you will need two pipes).

+1
source

It looks like you have IN / OUT back for the pipe - pipefd[0] is the read end of the pipe, so writing to it (as the parent does) is pointless and will fail. Similarly, pipefd[1] is the end of the record, so reading from it (as the parent does) will also fail. You should ALWAYS check the return values โ€‹โ€‹of read and write calls to see if you have any errors.

+1
source

Others say the pipe is unidirectional, and this is what I thought about at the beginning. But actually this is not what my page says:

  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. 

However, this means that if the parent writes to pipefd[0] , then the child must read from pipefd[1] , so you are linking the wrong side of the pipe to the child stdin and stdout.

On the man page, it seems you can do this with a single channel. But the code for using the two may be more clear.

You seem to think of each pipefd element as a separate pipefd , but that is not the case.

+1
source

Source: https://habr.com/ru/post/900322/


All Articles