Home > Software engineering >  pipe function returning random characters
pipe function returning random characters

Time:04-11

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    
    int main(void){
    
    //Variables, p[2] for each end of the pipe. nbytes to read pipe return value SUCCESS or FAILURE. pid_t to hold pid of fork process.
    // buffer to hold response from the child process.
        int     p[2], nbytes;
        pid_t   childpid;
        char    string[] = "Hello, World!\n";
        char    buffer[80];
    
    //Declaration of pipe
        pipe(p);
        
        //Error handling.
        if(((childpid = fork()) == -1) || (pipe(p) == -1))
        {
                perror("fork");
                exit(1);
        }
    
        //Child process sends message to paprent.
        if(childpid == 0)
        {
                /* Child process closes up input side of pipe */
                close(p[0]);
    
                /* Send "string" through the output side of pipe */
                write(p[1], string, (strlen(string) 1));
                exit(0);
        }
        else
        {
                /* Parent process closes up output side of pipe */
                close(p[1]);
    
                /* Read in a string from the pipe */
                nbytes = read(p[0], buffer, sizeof(buffer));
    
                printf("Received string: %s", buffer);
    
        }
        return(0);
    }

Output > Received string: @�=zJ

The point of the exercise is to have a child process send a message through a pipe to the parent process and the parent returns the result. This exact code worked the first time I ran it, but then when I tried to run it a second time it started to return seemingly random characters each time. I tried to copy my buffer to another variable but then it was empty. Is the pipe actually not function the way I think it is? What am I doing wrong?

CodePudding user response:

You first create a pipe with pipe(p); and then you create another with ... || (pipe(p) == -1)) Is that deliberate?

2nd Pipe was causing an issue.

CodePudding user response:

You have:

pipe(p);

//Error handling.
if(((childpid = fork()) == -1) || (pipe(p) == -1))
{
        perror("fork");
        exit(1);
}

This creates two pipes — one in the line pipe(p); and the second in the condition if(((childpid = fork()) == -1) || (pipe(p) == -1)). This is wasteful at best. Moreover, the second pipe is after the fork(), so the parent and child processes don't access the same pipe any more — you overwrote the one created before the fork() which they do share. Test the result of pipe() before calling fork() and remove the extra condition in the if test:

if (pipe(p) != 0)
{
    perror("pipe");
    exit(1);
}
if ((childpid = fork()) < 0)
{
    perror("fork");
    exit(1);
}

Get used to testing for errors and writing appropriate code to handle them. It will be a major part of your life as a C programmer.

Later on in the code, you have:

{
        /* Parent process closes up output side of pipe */
        close(p[1]);

        /* Read in a string from the pipe */
        nbytes = read(p[0], buffer, sizeof(buffer));

        printf("Received string: %s", buffer);

}

You need to heed the value of nbytes. Since it is an int, you could use:

printf("Received %d bytes: [%.*s]\n", nbytes, nbytes, buffer);

This limits the output to what was read, and reports 0 if that's what it gets. I suppose you should also check for -1 in nbytes before using it in the printf() statement:

if (nbytes < 0)
{
    fprintf(stderr, "failed to read from pipe descriptor %d\n", p[0]);
    // Or perror("read");
    // Should you exit here with a non-zero status?
}
else
    printf("Received %d bytes: [%.*s]\n", nbytes, nbytes, buffer);

Note: errors are reported on stderr; perror() does that automatically.

CodePudding user response:

The problem is that you create two pipes when you really only need to check the first for errors:

// Declaration of pipe
if(pipe(p) == -1) {               // check for error here
    perror("pipe");
    exit(1);
}

// Error handling.
if((childpid = fork()) == -1) { // and don't create another pipe here
    perror("fork");
    exit(1);
}

You should also check the return values from write and read. They may not write or read the full string in one go.

  •  Tags:  
  • c
  • Related