首页 > 解决方案 > Unable to send a message from a child process back to the parent process

问题描述

I am trying to understand how pipes and forking work. So I wrote a simple program where a parent process sends a message to the child process (which works fine). But if I try to send a message back from the child process by adding the commented code, it stops working. And the execution of the program stops after outputting "Parent sent: hello".

int main() {
    int child_to_parent[2];
    int parent_to_child[2];
    pipe(child_to_parent);
    pipe(parent_to_child);

    pid_t id = fork();

    if (id == 0) {
        close(parent_to_child[1]);
        close(child_to_parent[0]);
        FILE* out = fdopen(child_to_parent[1], "w");
        FILE* in = fdopen(parent_to_child[0], "r");

        char msg[6];
        fscanf(in ,"%s", msg);
        printf("Child got: %s\n", msg);
        /*
        fprintf(out, "hi ");
        printf("Child sent: hi\n"); 
        */
    } else {
        close(parent_to_child[0]);
        close(child_to_parent[1]);
        FILE* in = fdopen(child_to_parent[0], "r");
        FILE* out = fdopen(parent_to_child[1], "w");

        fprintf(out, "hello");
        printf("Parent sent: hello\n");
        /*
        char msg[3];
        fscanf(in, "%s", msg);
        printf("Parent got: %s\n", msg);
        */
    }
}

And I can't figure out why. What confuses me the most is why the child process can't even receive the message after I modified the code. Could anyone please tell me what's wrong, or direct me in the right direction?

标签: cpipefork

解决方案


First solution using read/write to exchange any number of messages

Here I indicate the end of each buffer to read by a \n :

#include <stdio.h>
#include <unistd.h>
#include <string.h>

void rd(int fd, int child)
{
  char c;
  int first = 1;

  do {
    if (!read(fd, &c, 1))
      break;
    if (first) {
      printf("%s got:", (child) ? "Child" : "Parent");
      first = 0;
    }
    putchar(c);
  } while (c != '\n');
}

void wr(int fd, const char * msg, int child)
{
  write(fd, msg, strlen(msg));
  printf("%s sent:%s", (child) ? "Child" : "Parent", msg);
}

int main() {
    int child_to_parent[2];
    int parent_to_child[2];

    pipe(child_to_parent);
    pipe(parent_to_child);

    pid_t id = fork();

    if (id == 0) {
      close(parent_to_child[1]);
      close(child_to_parent[0]);

      rd(parent_to_child[0], 1);
      wr(child_to_parent[1], "hi\n", 1);

      rd(parent_to_child[0], 1);
      wr(child_to_parent[1], "fine, and you ?\n", 1);

      rd(parent_to_child[0], 1);
    } else {
      close(parent_to_child[0]);
      close(child_to_parent[1]);

      wr(parent_to_child[1], "hello\n", 0);
      rd(child_to_parent[0], 0);

      wr(parent_to_child[1], "how are you ?\n", 0);
      rd(child_to_parent[0], 0);

      wr(parent_to_child[1], "fine too\n", 0);
    }
}

Compilation and execution :

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra p.c
pi@raspberrypi:/tmp $ ./a.out 
Parent sent:hello
Child got:hello
Child sent:hi
Parent got:hi
Parent sent:how are you ?
Child got:how are you ?
Child sent:fine, and you ?
Parent got:fine, and you ?
Parent sent:fine too
Child got:fine too

It is also possible to use fread/fwrite, fflush is necessary after fwrite to not be blocked. It is fortunately not necessary to close the pipe after sending to be able to read and answer, else only one message can be exchanged. I still use \n to indicate the end of the buffer sent :

#include <stdio.h>
#include <unistd.h>
#include <string.h>

void rd(FILE * fd, int child)
{
  char c;
  int first = 1;

  do {
    if (!fread(&c, 1, 1, fd))
      break;
    if (first) {
      printf("%s got:", (child) ? "Child" : "Parent");
      first = 0;
    }
    putchar(c);
  } while (c != '\n');
}

void wr(FILE *  fd, const char * msg, int child)
{
  fwrite(msg, strlen(msg), 1, fd);
  fflush(fd);
  printf("%s sent:%s", (child) ? "Child" : "Parent", msg);
}

int main() {
    int child_to_parent[2];
    int parent_to_child[2];
    pipe(child_to_parent);
    pipe(parent_to_child);

    pid_t id = fork();

    if (id == 0) {
        close(parent_to_child[1]);
        close(child_to_parent[0]);
        FILE* out = fdopen(child_to_parent[1], "w");
        FILE* in = fdopen(parent_to_child[0], "r");

    rd(in, 1);
    wr(out, "hi\n", 1);

    rd(in, 1);
    wr(out, "fine, and you ?\n", 1);

    rd(in, 1);
    } else {
        close(parent_to_child[0]);
        close(child_to_parent[1]);
        FILE* in = fdopen(child_to_parent[0], "r");
        FILE* out = fdopen(parent_to_child[1], "w");

    wr(out, "hello\n", 0);
    rd(in, 0);

    wr(out, "how are you ?\n", 0);
    rd(in, 0);

    wr(out, "fine too\n", 0);
    }
}

Compilation and execution:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra pp.c
pi@raspberrypi:/tmp $ ./a.out
Parent sent:hello
Child got:hello
Child sent:hi
Parent got:hi
Parent sent:how are you ?
Child got:how are you ?
Child sent:fine, and you ?
Parent got:fine, and you ?
Parent sent:fine too
Child got:fine too

And finally if you want to use fscanf("%s", ...) you need to sent a separator (a space or \n for instance) after the word to not block fscanf and of course to also read the separator character, the fflush is necessary after the fwrite.

If I change a little you program :

#include <stdio.h>
#include <unistd.h>

int main() {
    int child_to_parent[2];
    int parent_to_child[2];
    pipe(child_to_parent);
    pipe(parent_to_child);

    pid_t id = fork();

    if (id == 0) {
      close(parent_to_child[1]);
      close(child_to_parent[0]);
      FILE* out = fdopen(child_to_parent[1], "w");
      FILE* in = fdopen(parent_to_child[0], "r");
      char msg[16], c;

      fscanf(in ,"%s%c", msg, &c);
      printf("Child got: %s\n", msg);

      fprintf(out, "hi ");
      fflush(out);
      printf("Child sent: hi\n"); 

      fscanf(in ,"%s%c", msg, &c);
      printf("Child got: %s\n", msg);

      fprintf(out, "fine,you? ");
      fflush(out);
      printf("Child sent: fine,you?\n"); 

      fscanf(in ,"%s%c", msg, &c);
      printf("Child got: %s\n", msg);
    } else {
      close(parent_to_child[0]);
      close(child_to_parent[1]);
      FILE* in = fdopen(child_to_parent[0], "r");
      FILE* out = fdopen(parent_to_child[1], "w");

      fprintf(out, "hello\n");
      fflush(out);
      printf("Parent sent: hello\n");

      char msg[16], c;

      fscanf(in, "%s%c", msg, &c);
      printf("Parent got: %s\n", msg);

      fprintf(out, "how-are-you? ");
      fflush(out);
      printf("Parent sent: how-are-you?\n");

      fscanf(in, "%s%c", msg, &c);
      printf("Parent got: %s\n", msg);

      fprintf(out, "fine-too ");
      fflush(out);
      printf("Parent sent: fine-too\n");
    }
}

Compilation and execution :

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra ppp.c
pi@raspberrypi:/tmp $ ./a.out
Parent sent: hello
Child got: hello
Child sent: hi
Parent got: hi
Parent sent: how-are-you?
Child got: how-are-you?
Child sent: fine,you?
Parent got: fine,you?
Parent sent: fine-too
Child got: fine-too

推荐阅读