简体   繁体   中英

Creating pipes in C for inter process communication between multiple processes

There are already multiple answers to this question but none of them have been able to help me solve my problem. I am trying to understand IPC using an anonymous pipe in C. From my understanding of pipes, they are a one way communication channel with one read end and one write end.
Assuming we have two c files one named parent.c and the other child.c . What I am trying to achieve is to be able to create 5 or more child processes. After this the parent and the child should communicate with the child processes through standard input and standard output , but since I want to be able to print what the parent receives from the child I'll instead tie the pipes to standard error output using dup2 .
In summary
1. Run a parent program which spins up 5 or more child processes and runs them.
2. The child process waits for an input from the parent using scanf .
3. The parent sends a message to the child process.
4. The child process receives the message and sends a reply to the parent and exits.
5. The parent process prints the received message and prints it then exits.

parent.c

// Parentc
#include <stdio.h>
#include <stdlib.h>
#include <uinstd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, const char *argv[]){
        // File descriptors for the pipes
        int read_pipe[2]; // From child to parent
        int write_pipe[2]; // From parent to child

        pid_t process_id;
        int exit_status;

        // Try to fork 5 child processes
        for(int i = 0; i < 5; i++){
                if(pipe(write_pipe) == -1 || pipe(read_pipe) == -1){
                        perror("Pipe");
                        exit(1);
                }

                // Spin a child process
                process_id = fork();

                if(process_id == -1){
                        perror("Fork");
                        exit(1);
                } else if(processId == 0) {
                        // The child process
                        // I don't know what to do here, The idea is to close the
                        // unneeded end of the pipes and wait for input from the parent
                        // process

                         // Start the ./child
                        execl("./child", "");            

                } else {
                        // The parent process
                        char recieved_data[1024];

                        // Send data to child since stderr is duplicated in the pipe
                        // It sends the pid of the child
                         fprintf(stderr, "Test data to %d ", process_id);

                        // Wait to recieve data from child
                        // Don't know how to do that

                         // Print the recieved data
                        printf("Parent recieved: \"%s\"\n", recieved_data);

                        wait(&exit_status); // Will wait till all children exit before exiting
                }
        }

        return 0;
}

The child.c is a simple program as shown below

child.c

#include <stdio.h>

int main(int argc, const char *argv[]){
        char data_buffer[1024];

        // Wait for input from parent
        scanf("%s", data_buffer);

        // Send data back to parent
        printf("Child process: %s", data_buffer);

        return 0;
}

Expected output

$ ./parent
parent recived: "Child process: Test data to 12345"
parent recived: "Child process: Test data to 12346"
parent recived: "Child process: Test data to 12347"
parent recived: "Child process: Test data to 12348"
parent recived: "Child process: Test data to 12349"

Where 12345, 12346....12349 is the process id of the child process

Here you have a code i did, and i will use to explain to you:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    char buff[1024];
    int aux, i, count;
    int fds[2], fdss[2];
    pipe(fds); //Here we initialize the file descriptors
    pipe(fdss);
    mode_t fd_mode = S_IRWXU;

    for (i = 0; i < 3; i++) {
        aux = fork();
        if (aux == 0)
            break;
    }

    switch (i) {

        case 0:
            printf("Write something:\n");
            scanf("%s[^\n]", buff);
            i = 0;
            count = 0;
            while(buff[i] != '\0') {

                count++;
                i++;
            }
            dup2(fds[1], 1);
            close(fds[1]);
            close(fds[0]);
            close(fdss[0]);
            close(fdss[1]);
            write (1, buff, sizeof(buff));
            break;

        case 1:

            dup2(fds[0], 0);
            dup2(fdss[1], 1);
            close(fds[0]);
            close(fds[1]);
            close(fdss[0]);
            close(fdss[1]);
            // 
            if (execl("/bin/grep", "grep", "example", NULL) == -1) {
                printf("Error\n");
                exit (1);
            }

            break;

        case 2:
            aux = open("result.txt", O_RDWR | O_CREAT , S_IRWXU);

            dup2(fdss[0], 0);
            dup2(aux, 1);
            close(fds[0]);
            close(fds[1]);
            close(fdss[0]);
            close(fdss[1]);
            close(aux);
            if (execl("/usr/bin/wc", "wc", "-l", NULL) == -1) {
                printf("Error \n");
                exit (1);
            }

    }
            close(fds[0]);
            close(fds[1]);
            close(fdss[0]);
            close(fdss[1]);
    for (i = 0; i < 3; i++) wait(NULL);

    return 0;
}

Ok, let's start: We create and initialize pipes with pipe() Then we write our code and before execl() we change the file descriptors, in order to pass the text we will write in the console, through processes and finally write in a file called result.txt the result of the "grep example" command applied to the text we have written. The function dup2(new_descriptor, old_descriptor) is copying the new descriptor into the old descriptor and closes the old descriptor. For example: Before dup2(fds[1], 1) we have: 0 STDIN 1 STDOUT 2 STDERR After dup2(fds[1], 1) we have: 0 STDIN 1 fds[1] 2 STDERR NOTE: If you don't want to use 1, yo can simply write STDOUT_FILENO So now we are able to write through processes and in my example to a file too

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM