Search code examples
cforkdup2

communication between father and child dup()


I'm having really hard time figuring out the communication problem between the father and child. when i run the main program it seems like nothing happens. i did searched online for solution and nothing have helped me so far. i know i posted a lot of code out here but from my old post about the same problem people have send me to read the man again and again but still,something is not right here and i don't know what exactly . I hope you guys can help me

#include <stdio.h>
#include <stdlib.h> //for exit
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h> //for sleep(),execvp()
#include <ctype.h>
#include <fcntl.h>
#define IN 0
#define OUT 1
#define SIZE 81
#define EXEC "./child"

int main(int argc, char * argv[])
{
    int fd[2];
    int fdr;   // file descriptors
    int i;
    char result[3];
    pid_t pid;
    char charMatrix[SIZE] ={ 0 };
    int matrix[9][9]={0};
    if (argc < 2)
    {

        printf("No files added, abort program\n");
        exit(EXIT_FAILURE);
    }
    if (pipe(fd) == -1)
    {
        printf("Pipe Failed");
        return 1;
    }
    fdr = open(argv[1], O_RDONLY);   // open files
    if (fdr < 0)
    { //validation for error
        perror("failed to open input or output files");
        exit(EXIT_FAILURE); 
    }
    char c;

    charMatrix[81] = '\0';
    i=0;
    int j=0;
    while (read(fdr, &c, 1))          // read/write a single char
    {                                  // from/to the files
        if (c != ' ' && c != '\n')
        {
            charMatrix[i++]=c-'0';

        }


    }
    close(fdr);   // close the file
    int index=0;    //convert to matrix
    for (i = 0; i < 9; i++) { /* Iterate of each row */
            for (j = 0; j < 9; j++) { /* In each row, go over each col element  */
                matrix[i][j]=charMatrix[index++];
            }
        }
            for (i = 0; i < 9; i++) {//  Iterate of each row
            for (j = 0; j < 9; j++) {  //In each row, go over each col element
                printf("%d ", matrix[i][j]);//  Print each row element
            }
            printf("\n");//  Finish a row, start a new line
            }
    pid = fork();
    if (pid < 0)
    {
        fputs("error in fork", stderr);
        exit(EXIT_FAILURE);
    }
    //child
     if(pid == 0)
     {
                        close(fd[0]);
                close(STDOUT_FILENO);
                dup(fd[1]);
                        execl(EXEC, charMatrix, NULL);


     }
    //parent
     else{

        close(fd[1]);
        close(STDIN_FILENO);
        dup(fd[0]);
        read(fd[0], &result, sizeof(result));
        wait(NULL);

     }





    exit(EXIT_SUCCESS);
}

the file for the exec

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

int main(int argc, char * argv[]){

    int matrix[9][9];
    char charMatrix[81];
    char ans;
        int i, j;
        printf("got here");
        read(0,&charMatrix,sizeof(charMatrix));
    int index=0;    //convert to matrix
    for (i = 0; i < 9; i++) { /* Iterate of each row */
            for (j = 0; j < 9; j++) { /* In each row, go over each col element  */
                matrix[i][j]=charMatrix[index++];
            }
        }
    write(4, "a", sizeof(char));
    for (i = 0; i < 9; i++) { /* Iterate of each row */
        for (j = 0; j < 9; j++) { /* In each row, go over each col element  */
            printf("%d ", matrix[i][j]); /* Print each row element */
        }
        printf("\n"); /* Finish a row, start a new line */
    }
    exit(0);
}

After the solution that suggested i have tried to add another child but still got it wrong. here is the code and kind of an explanation how i see it

  dup2(pipe1[0], STDIN_FILENO); //makes the input( 0 in the stack) to the pipe1[0] which means point to its 
    close(pipe1[0]);
    close(pipe1[1]); //closing before pointes
    dup2(pipe2[1], STDOUT_FILENO); //makes the output (1 in the stack) to point pip1[1]
    close(pipe2[0]);
    close(pipe2[1]);//closing 
    execl(EXEC, EXEC, NULL);//exec

I have tried to do the same thing with the other child with new pipe but with no success. i dup the father pipe1 to the answer of the pipe3 of the second child

//-------------------------------------------------------------------//

#define SIZE 81
#define EXEC "./child"
#define EXEC2 "./child2"
int main(int argc, char *argv[])
{
    char charMatrix[SIZE] = { 0 };
    int matrix[9][9] = { 0 };
    char chilesStatus[3]={0};
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s matrix file \n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int fdr = open(argv[1], O_RDONLY);
    if (fdr < 0)
    {
        perror("failed to open input or output files");
        exit(EXIT_FAILURE);
    }

    char c;
    int k = 0;
    while (read(fdr, &c, 1) == 1 && k < (int)sizeof(charMatrix))
    {
        if (c != ' ' && c != '\n')
            charMatrix[k++] = c - '0';
    }

    close(fdr);

    int index = 0;
    for (int i = 0; i < 9; i++)
    {
        for (int j = 0; j < 9; j++)
            matrix[i][j] = charMatrix[index++];
    }

    printf("Input matrix:\n");
    for (int i = 0; i < 9; i++)
    {
        printf("P: ");
        for (int j = 0; j < 9; j++)
            printf(" %d", matrix[i][j]);
        printf("\n");
    }
    fflush(stdout);     // Making sure output is flushed even if it is going to a pipe

    int pipe1[2];
    int pipe2[2];
    int pipe3[2];
    int pipe4[2];

    if (pipe(pipe1) == -1 || pipe(pipe2) == -1 || pipe(pipe3) == -1) //pipe validation
    {
        perror("Pipe failed");
        exit(EXIT_FAILURE);
    }

    pid_t fChild = fork();
    if (fChild < 0)
    {
        perror("Fork failed");
        exit(EXIT_FAILURE);
    }

    if (fChild == 0)
    {
        dup2(pipe1[0], STDIN_FILENO);
        close(pipe1[0]);
        close(pipe1[1]);
        dup2(pipe2[1], STDOUT_FILENO);
        close(pipe2[0]);
        close(pipe2[1]);
        execl(EXEC, EXEC, NULL);
        int errnum = errno;
        fprintf(stderr, "Failed to execute '%s' (%d: %s)\n", EXEC, errnum, strerror(errnum));
        exit(EXIT_FAILURE);
    }

    else
    {
        pid_t sChild = fork();
        if(sChild==0)
        {
                dup2(pipe2[0], STDIN_FILENO);
                    close(pipe2[0]);
                    close(pipe2[1]);
                    dup2(pipe3[1], STDOUT_FILENO);
                    close(pipe3[0]);
                    close(pipe3[1]);
                    execl(EXEC2, EXEC2, NULL);
                    int errnum = errno;
                    fprintf(stderr, "Failed to execute '%s' (%d: %s)\n", EXEC, errnum, strerror(errnum));
                    exit(EXIT_FAILURE);
        }
        else
        {

        }
    close(pipe2[0]);
        close(pipe1[0]);
        if (write(pipe1[1], charMatrix, sizeof(charMatrix)) != sizeof(charMatrix))
        {
            perror("failed to write to child");
            exit(EXIT_FAILURE);
        }
    if (write(pipe1[2], charMatrix, sizeof(charMatrix)) != sizeof(charMatrix))
        {
            perror("failed to write to child");
            exit(EXIT_FAILURE);
        }
        close(pipe1[1]);
        close(pipe2[1]);
    close(pipe3[1]);
        char result[3];
        int nbytes = read(pipe2[0], &result, sizeof(result));
    int nbytes2 = read(pipe3[0], &result, sizeof(result));
        if (nbytes <= 0 ||nbytes2 <= 0) 
        {
            perror("Failed to read from pipe");
            exit(EXIT_FAILURE);
        }

        close(pipe2[0]);
    close(pipe3[0]);
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
            printf("Child %d exited with status 0x%.4X\n", corpse, status);

        printf("Received '%.*s' from child\n", nbytes, result);
    }

    return(EXIT_SUCCESS);
}

Solution

  • One child process

    Major revisions to both source files — parent.c and child.c.

    parent.c

    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <unistd.h>
    
    #define SIZE 81
    #define EXEC "./child"
    
    int main(int argc, char *argv[])
    {
        char charMatrix[SIZE] = { 0 };
        int matrix[9][9] = { 0 };
    
        if (argc != 2)
        {
            fprintf(stderr, "Usage: %s matrixfile\n", argv[0]);
            exit(EXIT_FAILURE);
        }
    
        int fdr = open(argv[1], O_RDONLY);
        if (fdr < 0)
        {
            perror("failed to open input or output files");
            exit(EXIT_FAILURE);
        }
    
        char c;
        int k = 0;
        while (read(fdr, &c, 1) == 1 && k < (int)sizeof(charMatrix))
        {
            if (c != ' ' && c != '\n')
                charMatrix[k++] = c - '0';
        }
    
        close(fdr);
    
        int index = 0;
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
                matrix[i][j] = charMatrix[index++];
        }
    
        printf("Input matrix:\n");
        for (int i = 0; i < 9; i++)
        {
            printf("P: ");
            for (int j = 0; j < 9; j++)
                printf(" %d", matrix[i][j]);
            printf("\n");
        }
        fflush(stdout);     // Make sure output is flushed even it it is going to a pipe
    
        int pipe1[2];
        int pipe2[2];
        if (pipe(pipe1) == -1 || pipe(pipe2) == -1)
        {
            perror("Pipe failed");
            exit(EXIT_FAILURE);
        }
    
        pid_t pid = fork();
        if (pid < 0)
        {
            perror("Fork failed");
            exit(EXIT_FAILURE);
        }
    
        if (pid == 0)
        {
            dup2(pipe1[0], STDIN_FILENO);
            close(pipe1[0]);
            close(pipe1[1]);
            dup2(pipe2[1], STDOUT_FILENO);
            close(pipe2[0]);
            close(pipe2[1]);
            execl(EXEC, EXEC, NULL);
            int errnum = errno;
            fprintf(stderr, "Failed to execute '%s' (%d: %s)\n", EXEC, errnum, strerror(errnum));
            exit(EXIT_FAILURE);
        }
    
        else
        {
            close(pipe1[0]);
            if (write(pipe1[1], charMatrix, sizeof(charMatrix)) != sizeof(charMatrix))
            {
                perror("failed to write to child");
                exit(EXIT_FAILURE);
            }
            close(pipe1[1]);
    
            close(pipe2[1]);
            char result[3];
            int nbytes = read(pipe2[0], &result, sizeof(result));
            if (nbytes <= 0)
            {
                perror("Failed to read from pipe");
                exit(EXIT_FAILURE);
            }
            close(pipe2[0]);
    
            int corpse;
            int status;
            while ((corpse = wait(&status)) > 0)
                printf("Child %d exited with status 0x%.4X\n", corpse, status);
    
            printf("Received '%.*s' from child\n", nbytes, result);
        }
    
        return(EXIT_SUCCESS);
    }
    

    child.c

    #include <stdio.h>
    #include <sys/stat.h>
    #include <unistd.h>
    
    int main(void)
    {
        int matrix[9][9];
        char charMatrix[81];
    
        fprintf(stderr, "got here\n");
        int nbytes = read(STDIN_FILENO, charMatrix, sizeof(charMatrix));
        fprintf(stderr, "got %d bytes\n", nbytes);
        int index = 0;
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
                matrix[i][j] = charMatrix[index++];
        }
    
        write(STDOUT_FILENO, "a", sizeof(char));
        fprintf(stderr, "Ack written to parent\n");
    
        fprintf(stderr, "Child matrix:\n");
        for (int i = 0; i < 9; i++)
        {
            fprintf(stderr, "C: ");
            for (int j = 0; j < 9; j++)
                fprintf(stderr, " %d", matrix[i][j]);
            fprintf(stderr, "\n");
        }
    
        return(0);
    }
    

    Random matrix

    6 9 4 5 3 2 6 1 2
    2 7 1 5 1 9 1 5 7
    1 5 3 1 6 6 7 1 8
    6 3 2 4 2 8 9 5 2
    2 2 7 9 4 1 3 7 7
    3 1 7 8 6 5 5 2 4
    6 5 9 1 6 7 7 8 7
    5 4 9 5 1 8 9 2 1
    3 5 6 8 3 6 9 6 9
    

    Output

    $ ./parent random.matrix
    Input matrix:
    P:  6 9 4 5 3 2 6 1 2
    P:  2 7 1 5 1 9 1 5 7
    P:  1 5 3 1 6 6 7 1 8
    P:  6 3 2 4 2 8 9 5 2
    P:  2 2 7 9 4 1 3 7 7
    P:  3 1 7 8 6 5 5 2 4
    P:  6 5 9 1 6 7 7 8 7
    P:  5 4 9 5 1 8 9 2 1
    P:  3 5 6 8 3 6 9 6 9
    got here
    got 81 bytes
    Ack written to parent
    Child matrix:
    C:  6 9 4 5 3 2 6 1 2
    C:  2 7 1 5 1 9 1 5 7
    C:  1 5 3 1 6 6 7 1 8
    C:  6 3 2 4 2 8 9 5 2
    C:  2 2 7 9 4 1 3 7 7
    C:  3 1 7 8 6 5 5 2 4
    C:  6 5 9 1 6 7 7 8 7
    C:  5 4 9 5 1 8 9 2 1
    C:  3 5 6 8 3 6 9 6 9
    Child 9498 exited with status 0x0000
    Received 'a' from child
    $
    

    Two child processes

    It isn't entirely clear why you define but don't use pipe4 in your revised code. I decided it would be easier that way. As you move from 1 to 2 processes, the naming conventions with digit suffixes become creaky (but the code below still uses it). It would be better to think in terms of arrays. I revised the child processes to send bigger messages, and the parent code to receive them — it gives better identification of what's going on. The output from the children can be interleaved.

    I'm not clear how you envisaged the trio of pipes working. Using four pipes, pipes 1 and 2 connect to child 1; pipes 3 and 4 to child 2. The odd number pipe conveys information to the child; the even number pipe conveys information from the child. There are lots of calls to close().

    pipe47.c

    /* SO 5609-3694 */
    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <unistd.h>
    
    #define SIZE 81
    #define EXEC1 "./child2"
    #define EXEC2 "./child2"
    
    int main(int argc, char *argv[])
    {
        char charMatrix[SIZE] = { 0 };
        int matrix[9][9] = { 0 };
    
        if (argc != 2)
        {
            fprintf(stderr, "Usage: %s matrix file \n", argv[0]);
            exit(EXIT_FAILURE);
        }
    
        int fdr = open(argv[1], O_RDONLY);
        if (fdr < 0)
        {
            perror("failed to open input or output files");
            exit(EXIT_FAILURE);
        }
    
        char c;
        int k = 0;
        while (read(fdr, &c, 1) == 1 && k < (int)sizeof(charMatrix))
        {
            if (c != ' ' && c != '\n')
                charMatrix[k++] = c - '0';
        }
    
        close(fdr);
    
        int index = 0;
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
                matrix[i][j] = charMatrix[index++];
        }
    
        printf("Input matrix:\n");
        for (int i = 0; i < 9; i++)
        {
            printf("P: ");
            for (int j = 0; j < 9; j++)
                printf(" %d", matrix[i][j]);
            printf("\n");
        }
        fflush(stdout);     // Making sure output is flushed even if it is going to a pipe
    
        int pipe1[2];
        int pipe2[2];
        int pipe3[2];
        int pipe4[2];
    
        if (pipe(pipe1) == -1 || pipe(pipe2) == -1 || pipe(pipe3) == -1 || pipe(pipe4) == -1) // pipe validation
        {
            perror("Pipe failed");
            exit(EXIT_FAILURE);
        }
    
        pid_t fChild = fork();
        if (fChild < 0)
        {
            perror("Fork failed (child 1)");
            exit(EXIT_FAILURE);
        }
    
        if (fChild == 0)
        {
            dup2(pipe1[0], STDIN_FILENO);
            dup2(pipe2[1], STDOUT_FILENO);
            close(pipe1[0]);
            close(pipe1[1]);
            close(pipe2[0]);
            close(pipe2[1]);
            close(pipe3[0]);
            close(pipe3[1]);
            close(pipe4[0]);
            close(pipe4[1]);
            execl(EXEC1, EXEC1, NULL);
            int errnum = errno;
            fprintf(stderr, "Failed to execute '%s' (1) (%d: %s)\n", EXEC1, errnum, strerror(errnum));
            exit(EXIT_FAILURE);
        }
    
        pid_t sChild = fork();
        if (sChild < 0)
        {
            perror("Fork failed (child 2)");
            exit(EXIT_FAILURE);
        }
    
        if (sChild == 0)
        {
            dup2(pipe3[0], STDIN_FILENO);
            dup2(pipe4[1], STDOUT_FILENO);
            close(pipe1[0]);
            close(pipe1[1]);
            close(pipe2[0]);
            close(pipe2[1]);
            close(pipe3[0]);
            close(pipe3[1]);
            close(pipe4[0]);
            close(pipe4[1]);
            execl(EXEC2, EXEC2, NULL);
            int errnum = errno;
            fprintf(stderr, "Failed to execute '%s' (2) (%d: %s)\n", EXEC2, errnum, strerror(errnum));
            exit(EXIT_FAILURE);
        }
    
        close(pipe1[0]);
        close(pipe2[1]);
        close(pipe3[0]);
        close(pipe4[1]);
    
        if (write(pipe1[1], charMatrix, sizeof(charMatrix)) != sizeof(charMatrix))
        {
            perror("failed to write to child 1");
            exit(EXIT_FAILURE);
        }
        close(pipe1[1]);
    
        if (write(pipe3[1], charMatrix, sizeof(charMatrix)) != sizeof(charMatrix))
        {
            perror("failed to write to child 2");
            exit(EXIT_FAILURE);
        }
        close(pipe3[1]);
    
        char result1[64];
        int nbytes1 = read(pipe2[0], &result1, sizeof(result1));
        close(pipe2[0]);
        if (nbytes1 <= 0)
        {
            perror("Failed to read from child 1");
            exit(EXIT_FAILURE);
        }
    
        char result2[64];
        int nbytes2 = read(pipe4[0], &result2, sizeof(result2));
        close(pipe4[0]);
        if (nbytes2 <= 0)
        {
            perror("Failed to read from child 2");
            exit(EXIT_FAILURE);
        }
    
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
            printf("Child %d exited with status 0x%.4X\n", corpse, status);
    
        printf("Received '%.*s' from child 1\n", nbytes1, result1);
        printf("Received '%.*s' from child 2\n", nbytes2, result2);
    
        return(EXIT_SUCCESS);
    }
    

    child2.c

    /* SO 5609-3694 */
    #include <stdio.h>
    #include <sys/stat.h>
    #include <unistd.h>
    
    int main(void)
    {
        int matrix[9][9];
        char charMatrix[81];
        int pid = getpid();
    
        fprintf(stderr, "PID %d: got here\n", pid);
        int nbytes = read(STDIN_FILENO, charMatrix, sizeof(charMatrix));
        fprintf(stderr, "PID %d: got %d bytes\n", pid, nbytes);
        int index = 0;
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
                matrix[i][j] = charMatrix[index++];
        }
    
        //write(STDOUT_FILENO, "a", sizeof(char));
        printf("PID %d: message received", pid);
        fprintf(stderr, "PID %d: Ack written to parent\n", pid);
    
        fprintf(stderr, "PID %d: Child matrix:\n", pid);
        for (int i = 0; i < 9; i++)
        {
            fprintf(stderr, "PID %d: ", pid);
            for (int j = 0; j < 9; j++)
                fprintf(stderr, " %d", matrix[i][j]);
            fprintf(stderr, "\n");
        }
    
        return(0);
    }
    

    Output

    Note that the output from the two children is interspersed with each other. One could devise mechanisms to avoid that.

    $ ./pipe47 random.matrix
    Input matrix:
    P:  6 9 4 5 3 2 6 1 2
    P:  2 7 1 5 1 9 1 5 7
    P:  1 5 3 1 6 6 7 1 8
    P:  6 3 2 4 2 8 9 5 2
    P:  2 2 7 9 4 1 3 7 7
    P:  3 1 7 8 6 5 5 2 4
    P:  6 5 9 1 6 7 7 8 7
    P:  5 4 9 5 1 8 9 2 1
    P:  3 5 6 8 3 6 9 6 9
    PID 11903: got here
    PID 11903: got 81 bytes
    PID 11903: Ack written to parent
    PID 11903: Child matrix:
    PID 11903:  6 9 4 5 3 2 6 1 2
    PID 11903:  2 7 1 5 1PID 11904: got here
     9 1 5 7
    PID 11903:  1 5 3 1PID 11904: got 81 bytes
     6 6 7 1 8
    PID 11903:  6 3 2PID 11904: Ack written to parent
     4PID 11904: Child matrix:
     2PID 11904:  8 6 9 9 5 4 2 5
     3PID 11903:  2 2 6 2 1 7 2 9 4 1
     3PID 11904:  7 2 7 7
     1PID 11903:  5 3 1 1 9 7 1 8 5 6 7 5
     5PID 11904:  2 1 4 5
     3PID 11903:  1 6 6 5 6 9 7 1 1 6 8 7
     7PID 11904:  8 6 7 3
     2PID 11903:  4 5 2 4 8 9 9 5 5 1 2 8
     9PID 11904:  2 2 1 2
     7PID 11903:  9 3 4 5 1 6 3 8 7 3 7 6
     9PID 11904:  6 3 9 1
     7 8 6 5 5 2 4
    PID 11904:  6 5 9 1 6 7 7 8 7
    PID 11904:  5 4 9 5 1 8 9 2 1
    PID 11904:  3 5 6 8 3 6 9 6 9
    Child 11903 exited with status 0x0000
    Child 11904 exited with status 0x0000
    Received 'PID 11903: message received' from child 1
    Received 'PID 11904: message received' from child 2
    $