Saturday, November 15, 2014

Unix Prog: IPC: FIFO

1. FIFO File
Pipes can be used only between related processes when a common ancestor has created the pipe.
With FIFO, unrelated processes can exchange data.

FIFO is a type of file, st_mode member of the stat structure indicates that a file is FIFO. http://dreamchaser1986unixdev.blogspot.com/2014/08/unix-prog-files-types_19.html

System Call used to create the FIFO file:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/stat.h  
 ......  
 /* Create a new FIFO named PATH, with permission bits MODE. */  
 extern int mkfifo (const char *__path, __mode_t __mode)  
    __THROW __nonnull ((1));  
 ......  

Once the FIFO file is created, we can open, read, write, close, unlink it like treating regular files.

If the O_NONBLOCK bit is not set in FIFO file descriptor:
1) An open for read will block until some other process open it for writing. And a write will block until some other process open it for reading.
Otherwise:
2) An open for read will return immediately. open for write-only returns -1 with errno set to ENXIO if no process has the FIFO for reading.

If there are multiple writers writing to the same FIFO, we need to make sure each write is atomic to avoid interleaving different writes. As long as the data amount get written doesn't exceed the PIPE_BUF, each write is atomic.

Usage of FIFO:
1) Used by shell commands to pass data from one shell pipelines to another without creating intermediate temp files
2) Used as rendezvous point in client-server applications to pass data between clients and server.

2. Example:
tr.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
   
 int main(int argc, char* argv[])  
 {  
  char line[20];  
  fgets(line, 20, stdin);  
  fputs(line, stdout);  
   
  exit(0);  
 }  

tr2.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
   
 int main(int argc, char* argv[])  
 {  
  char line[20];  
  fgets(line, 20, stdin);  
  fputs("tr2.out:", stdout);  
  fputs(line, stdout);  
   
  exit(0);  
 }  

shell:
mkfifo creates one FIFO file from the shell;
tr2.out reads from fifo , but right now no processes write to fifo, so tr2.out block there.
launch the tr.out to read from text file and then pipe to "tee", whose job is to pass text from standard input to standard output and the fifo file specified after "tee".

So the final output includes 2 lines:
first line is the text from tr.out, output to standard output
second line is the text from tr2.out, tr2.out get the text from fifo, which is then from tee.
 ubuntu@ip-172-31-23-227:~$ mkfifo fifo
 ubuntu@ip-172-31-23-227:~$ ./tr2.out < fifo &  
 [1] 1536  
 ubuntu@ip-172-31-23-227:~$ ./tr.out < text | tee fifo  
 Hello world!  
 tr2.out:Hello world!  

Following diagram can illustrate this:


2. Client Server Communication Example

In client-server communication model, server has one well-known FIFO, which is used to receive different requests sent from clients. If client specified the process id in the request, then after server process the request, server can build the client-specific FIFO to send reply back to client.

For example, if client's process id is 122, then server can create the FIFO called: client_122, then process 122 can use this FIFO specifically to receive the reply from server.

Problem:
If the client crashes, it will leave the client-specific FIFO in file system.
The server also need to catch the SIGPIPE, since it is possible that client send request and then terminate before receiving the reply.

No comments:

Post a Comment