Communications Via Pipes

Named Pipes

One limitation of anonymous pipes is that only processes 'related' to the process that created the pipe (i.e. siblings of that process.) may communicate using them. If we want two un-related processes to communicate via pipes, we need to use named pipes.


What Is A Named Pipe?

A named pipe (also called a named FIFO, or just FIFO) is a pipe whose access point is a file kept on the file system. By opening this file for reading, a process gets access to the reading end of the pipe. By opening the file for writing, the process gets access to the writing end of the pipe. If a process opens the file for reading, it is blocked until another process opens the file for writing. The same goes the other way around.


Creating A Named Pipe With The mknod Command

A named pipe may be created either via the 'mknod' (or its newer replacement, 'mkfifo'), or via the mknod() system call (or by the POSIX-compliant mkfifo() function). To create a named pipe with the file named 'prog_pipe', we can use the following command:

mknod prog_pipe p

We could also provide a full path to where we want the named pipe created. If we then type 'ls -l prog_pipe', we will see something like this:


prw-rw-r--   1 choo     choo            0 Nov  7 01:59 prog_pipe

The 'p' on the first column denotes this is a named pipe. Just like any file in the system, it has access permissions, that define which users may open the named pipe, and whether for reading, writing or both.


Opening A Named Pipe For Reading Or Writing

Opening a named pipe is done just like opening any other file in the system, using the open() system call, or using the fopen() standard C function. If the call succeeds, we get a file descriptor (in the case of open(), or a 'FILE' pointer (in the case of fopen()), which we may use either for reading or for writing, depending on the parameters passed to open() or to fopen().


Reading/Writing From/To A Named Pipe

Reading from a named pipe is very similar to reading from a file, and the same goes for writing to a named pipe. Yet there are several differences:

  1. Either Read Or Write - a named pipe cannot be opened for both reading and writing. The process opening it must choose one mode, and stick to it until it closes the pipe.
  2. Read/Write Are Blocking - when a process reads from a named pipe that has no data in it, the reading process is blocked. It does not receive an end of file (EOF) value, like when reading from a file. When a process tries to write to a named pipe that has no reader (e.g. the reader process has just closed the named pipe), the writing process gets blocked, until a second process re-opens the named pipe.

Thus, when writing a program that uses a named pipe, we must take these limitations into account. We could also turn the file descriptor via which we access the named pipe to a non-blocking mode.


Named Pipe - A Complete Example

As an example to an obscure usage of named pipes, we will borrow some idea from a program that allows one to count how many times they have been "fingered" lately. As you might know, on many Unix systems, there is a finger daemon, that accepts requests from users running the "finger" program, with a possible user name, and tells them when this user last logged on, as well as some other information. Amongst other thing, the finger daemon also checks if the user has a file named '.plan' (that is dot followed by "plan") in her home directory. If there is such a file, the finger daemon opens it, and prints its contents to the client. For example, on my Linux machine, fingering my account might show something like:


[choo@simey1 ~]$ finger choo
Login: choo                             Name: guy keren
Directory: /home/choo                   Shell: /bin/tcsh
On since Fri Nov  6 15:46 (IDT) on tty6
No mail.
Plan:
- Breed a new type of dogs.
- Water the plants during all seasons.
- Finish the next tutorial on time.

As you can see, the contents of the '.plan' file has been printed out.

This feature of the finger daemon may be used to create a program that tells the client how many times i was fingered. For that to work, we first create a named pipe, where the '.plan' file resides:

mknod /home/choo/.plan p

If i now try to finger myself, the output will stop before showing the 'plan' file. How so? this is because of the blocking nature of a named pipe. When the finger daemon opens my '.plan' file, there is no write process, and thus the finger daemon blocks. Thus, don't run this on a system where you expect other users to finger you often.

The second part of the trick, is compiling the named-pipe-plan.c program, and running it. note that it contains the full path to the '.plan' file, so change that to the appropriate value for your account, before compiling it. When you run the program, it gets into an endless loop of opening the named pipe in writing mode, write a message to the named pipe, close it, and sleep for a second. Look at the program's source code for more information. A sample of its output looks like this:


[choo@simey1 ~]$ finger choo
Login: choo                             Name: guy keren
Directory: /home/choo                   Shell: /bin/tcsh
On since Fri Nov  6 15:46 (IDT) on tty6
No mail.
Plan:
I have been fingered 8 times today

When you're done playing, stop the program, and don't forget to remove the named pipe from the file system.