Implementing Pipes in C

Pipes are an older but still useful mechanism for interprocess communication. Basically, pipes connect one process’s output to another process’s input. Data passes through a pipe sequentially, with bytes being read from the pipe in the same order they were written to the pipe.

There are both named and unnamed pipes. Unnamed pipes never have a pathname.

We use the pipe() function to create a pipe. The pipe() system call returns -1 if an error occurs. 

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

int main(void){

    int myPipe[2];

    if((pipe(myPipe))<0){
        printf("Error creating pipe.\n");
        exit(EXIT_FAILURE);
    }    

    printf("Descriptors are %d and %d\n", myPipe[0], myPipe[1]);

    return 0;

}

The pipe() system call opens two file descriptors and stores them in an int array. The first descriptor is stored in the first element of the array, and is used for reading. The second descriptor is located in the last element of the int array, and is used for writing.

Data travels in one direction through a pipe. One end is used for writing, and the other is used for reading. We can use the read() and write() call to read and write to pipes.

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


#define BUFFER_MAX 255

int main(void){

    char s[BUFFER_MAX+1] = {"With sufficient thrust, pigs fly just fine."};
    char buffer[BUFFER_MAX+1];

    int readLength, myPipe[2];

    if((pipe(myPipe))<0){
        printf("Error creating pipe.\n");
        exit(EXIT_FAILURE);
    }

    printf("writing '%s' to the pipe\n", s);
    
    //write message into the pipe
    write(myPipe[1], s, strlen(s));

    //read the message from the pipe
    readLength = read(myPipe[0], buffer, BUFFER_MAX);
    
    buffer[readLength]='';

    printf("%s\n", buffer);
    
close(myPipe[0]);
close(myPipe[1]);
    
    return 0;

}

Typically, an unnamed path is created in a parent process and then handed to a child process so that the two processes can communicate.  Because a child process inherits any open file descriptors from its parent, it can communicate with its parent. While it is possible for both parent and child processes to both read and write from the pipe, typically one process closes the write file descriptor, the reference to which is stored at index 1, and the other process closes the read file descriptor, the reference to which is stored at index 0.

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

int main(void){

    int fileDescription[2];
    
    int returnVal;

    if(pipe(fileDescription)<0){
        printf("Error opening pipe.\n");
        exit(EXIT_FAILURE);
    }

    if((returnVal=fork())<0){
        printf("Error forking.\n");
        exit(EXIT_FAILURE);
    }

    if(returnVal==0){
        //close write end
        close(fileDes[1]);
    }

    if(returnVal>0){
        //close read end
        close(fileDes[0]);
    }


    return 0;

}

Remember, to connect two processes using a pipe, we follow the pipe() call with a fork() call. Remember as well that the write file descriptor is located at index 1 of the array, and the read file descriptor is located at index 0 of the array.

For our final program, we will send a simple string of characters from our parent process to our child process.

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

#define BUFFER_MAX 255

int main(void){

    int fd[2], messageLength, returnVal;

    char buffer[BUFFER_MAX+1];
    char message[BUFFER_MAX+1];

    if((pipe(fd)<0)){
        printf("Error creating pipe.\n");
        exit(EXIT_FAILURE);
    }

    if((returnVal=fork())<0){
        printf("Error forking.\n");
        exit(EXIT_FAILURE);    
    }
    
    //in child process
    if(returnVal==0){
        //close write descriptor
        close(fd[1]);
        messageLength = read(fd[0], buffer, BUFFER_MAX);
        buffer[messageLength] = '';
        printf("received: '%s'\n", buffer);    
        //close read descriptor
        close(fd[0]);
    }
    if(returnVal>0){
        //in parent process
        //close read descriptor
        close(fd[0]);
        //copy message
        char *s = "A strange game. The only winning move is not to play.";
        strcpy(message, s);
        //send message
        write(fd[1], message, strlen(message));
        //close write descriptor
        close(fd[1]);
        //wait for child process to finish
        waitpid(returnVal, NULL, 0);

        printf("Exiting parent process.\n");
        
        return 0;
    }
    

}


If you’re interested in learning standard C, take a look at my book http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s