Reading and Writing to/from FIFOs

A FIFO, also known as a named pipe, is a file that acts like a pipe. One process opens the FIFO for writing, and another for reading. We can use the mkfifo() library function to open up a named pipe. The mkfifo() function accepts two parameters, the first is the pathname of the FIFO, and the second is the FIFO’s mode. The mkfifo() function returns -1 on failure and 0 on success.

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>

int main(void){
    
    const char *pathname = "fifoTest";
    
    if((mkfifo(pathname, S_IRWXU | S_IRWXG))!=-1){
        printf("Pipe opened.\n");
    } else {
        printf("Could not open pipe.");
        printf(" %s\n", strerror(errno));
    }
    
    return 0;
    
}

We can remove the named pipe the same we would a regular file, by using the unlink() system call. The unlink() system call is defined in the <unistd.h> header file.

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

int main(void){
    
    char *path = "testingABC";
    
    if((mkfifo(path, S_IRWXU | S_IRWXG)) < 0){
        printf("Error creating named pipe.\n");
        printf("%s.\n", strerror(errno));
        exit(EXIT_FAILURE);
    } else {
        printf("Named pipe %s created.\n", path);
    }
    
    if(unlink(path)<0){
        printf("Error erasing file.\n");
    } else {
        printf("%s erased.\n", path);
    }
    
    return 0;
    
}

Once a FIFO has been created using mkfifo(), we can access it via open() and read() or write().

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

int main(void){
    
    int fd;
    char *pathname = "theFIFO";
    pid_t childPID;
    
    if((mkfifo(pathname, S_IRWXU | S_IRWXG))<0){
        printf("Could not create named pipe %s.\n", pathname);
        printf("%s.\n", strerror(errno));
        exit(EXIT_FAILURE);
    }
    
    if((childPID = fork())<0){
        printf("Error forking process in %u.\n", getpid());
        exit(EXIT_FAILURE);
    }
    //in the child process --------------------------
    if(!childPID){
        char *msg = "Do you have stairs in your house?";
        printf("In the child process %u.\n", getpid());
        if((fd = open(pathname, O_WRONLY))<0){
            printf("Error opening FIFO in %u.\n", getpid());
            exit(EXIT_FAILURE);
        } else {
            printf("FIFO opened in %u.\n", getpid());
            write(fd, msg, strlen(msg));
        }
        printf("Exiting process %u.\n", getpid());
    }
    //in the parent process
    if(childPID){
        char buffer[256];
        printf("In the parent process %u.\n", getpid());
        if((fd = open(pathname, O_RDONLY))<0){
            printf("Error opening FIFO in %u.\n", getpid());
            exit(EXIT_FAILURE);
        } else {
            printf("FIFO opened in %u.\n", getpid());
            read(fd, buffer, sizeof(buffer));
            printf("In process %u, read: %s.\n", getpid(), buffer);
        }
        if((unlink(pathname))<0){
            printf("Error erasing %s.\n", pathname);
        } else {
            printf("FIFO '%s' erased.\n", pathname);
        }
        printf("Exiting process %u.\n", getpid());
    }
    
    return 0;
    
}

Note that the read() and write() functions operate slightly differently if we use the O_NONBLOCK flag to open the file descriptor, but that is a subject for another time.

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