I've been trying to wrap my head around FIFO, and came up with a simple program of server and client.
I'm not trying to do anything fancy, just to have one process that will play a role of 'server', this process will 'listen' to any messages delivered by another process; the client.
Here's what I wrote:
server.c
#include<stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#define INGOING "clientToServer.fifo"
#define BUFFER 200
int main(int argc, char *argv[]) {
char in[BUFFER];
mkfifo(INGOING, 0666);
printf("Welcome to server.\n");
printf("channel for sending messages to server is %s\n", INGOING);
int in_fd=open(INGOING, O_RDONLY);
if (in_fd==-1) {
perror("open error");
exit(-1);
}
while (read(in_fd, in, BUFFER)>0) {
printf("You sent %s to server.\n", in);
}
return 2;
}
As you can see, this is pretty straight forward, when I ran this at background with ./server.out&
it's blocked at the read
call and waiting for anyone to write to clientToServer.fifo
. so far so good.
Now, consider the client end:
client.c
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#define BUFFER 200
int main(int argc, char *argv[]) {
char input[BUFFER]={0};
int out_fd=open("clientToServer.fifo", O_WRONLY);
if (out_fd==-1) {
perror("open error");
}
while (1) {
printf("What would you like to send to server? (send Quit to quit)\n");
fgets(input, BUFFER, stdin);
if (input[strlen(input)-1]=='\n') {
input[strlen(input)-1]='\0';
}
if (strcmp(input, "Quit")==0) {
printf("Bye!");
break;
}
if (write(out_fd, input, strlen(input))==-1) {
perror("write error");
}
}
return 1;
}
This is the client. also pretty simple code. when I run it with ./a.out
from shell, it works - it sends the message, and the server.out
process prints You sent %s to server.
Problem is, when I send Quit
through the client to the server, although the a.out
process terminates as desired, the while
loop in the server.out
breaks as well. meaning, the read
no longer blocks the server.out
process and awaits other clients, instead, the server program ends, along with the client.
Why is this happening? shouldn't the read
suspend the server.out
again, even after the a.out
process ends?
When a user process attempts to read from an empty pipe (or FIFO), the following happens: If one end of the pipe is closed, 0 is returned, indicating the end of the file. If the write side of the FIFO has closed, read(2) returns 0 to indicate the end of the file.
A FIFO file is a special kind of file on the local storage which allows two or more processes to communicate with each other by reading/writing to/from this file. A FIFO special file is entered into the filesystem by calling mkfifo() in C.
A named pipe, also called a FIFO, is a pipe identified by an entry in a file system's name space. FIFOs are created using mknod(2), mkfifo(3C), or the mknod(1M) command.
The pipe has no name; it is created for one use and both ends must be inherited from the single process which created the pipe. A FIFO special file is similar to a pipe, but instead of being an anonymous, temporary connection, a FIFO has a name or names like any other file.
when I ran this at background with ./server.out& it's blocked at the read call and waiting for anyone to write to clientToServer.fifo
Actually it blocks at the open
. This is the way FIFOs work. The open
(in blocking mode) is going to block until something opens the FIFO on the other end.
the while loop in the server.out breaks as well. meaning, the read no longer blocks the server.out process and awaits other clients, instead, the server program ends
Again, this is normal behavior. Only one client process is connected to the FIFO so when it closes its end then EOF is sent and the server quits. If multiple clients are attached to the FIFO at the same time you won't see EOF until the last client closes it. If you want a long running server to serve multiple clients continuously the easiest way to accomplish it is to open the server's FIFO as read/write. This way there is always a reader/writer - the server itself - and you won't see EOF when even the last client exits. When it is time to shut down the server then close the appropriate end in the server and let nature take its course as the real clients quit.
When the client exits it closes the pipe connection, which causes the read
function in the server to return 0
which exits the loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With