Insane Coder Insane Coder - 6 months ago 24
Linux Question

Linux : Creating a simple non-blocking server and client to communicate over named pipes

I am trying to create a simple example of named pipes (FIFO). Here, the server will listen for message from the client, which writes on the named pipe, common to both of them. The special thing to be implemented is that the FIFO should be non-blocking (usage of

O_NONBLOCK
).

By non blocking, I mean that the writer should return immediately after writing, if there is no reader. Similarly, reader should return immediately if there is no message(no writer).

I have created the blocking version though and its working fine. I am then trying to convert it to non-blocking.

Here's the client :

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

#define FIFO "/tmp/myFIFO"

/*
This acts as the client, writing to the FIFO
*/

int main(int argc, char *argv[])
{
FILE *fp;
int fifo_fd;

if(argc != 2)
{
printf("Usage : ./fifo_client <message> \n");
exit(1);
}

fifo_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
if(fifo_fd < 0)
{
perror("Error while open call");
exit(1);
}
fp = fdopen(fifo_fd, "w");
if(fp == NULL)
{
perror("Error while opening fd");
exit(1);
}

fputs(argv[1],fp);

/* Close the fp */
fclose(fp);
return 0;
}


Here's the server :

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

#define FIFO "/tmp/myFIFO"

/*
This acts as a server waiting for strings to be written by the client, over the FIFO
*/

int main()
{
FILE *fp;
int fifo_fd;
char buf[1024];

/* Create a FIFO */
umask(0);
if(mkfifo(FIFO,0666) < 0) /* 0666 is read and write permission*/
{
perror("Error creating FIFO");
exit(1);
}


while(1) /*endless wait, keep reading strings and print*/
{
fifo_fd = open(FIFO, O_RDONLY | O_NONBLOCK);
if(fifo_fd < 0)
{
perror("Error while open call");
exit(1);
}
fp = fdopen(fifo_fd, "w");
if(fp == NULL)
{
perror("Error while opening fd");
exit(1);
}

if(!fgets(buf,1024,fp))
printf("Nothing to read\n");
else
printf("Message Recieved : %s\n", buf);
fclose(fp);
sleep(1);
}

return 0;
}


I run the server first.

Secondly, on second terminal, when I run the client, I get the error :

Error while open call: No such device or address


What am I missing? I did
man
, and the parameters seem to be correct.

EDIT

Moving the
open
and
close
calls out of the while loop, did the job. But now if the client is started without starting the server, throws the following error :

Error while open call: No such device or address

The file
/tmp/myFIFO
exists on file-system from previous execution of the server, must be used by the client.

Answer

The main problem is opening and closing the file in a loop. This makes no sense. There is a very short time interval between opening and closing, and your client must hit it. It has little chance to do so. The "No such device or address" message happens exactly because the client misses the instant when the file is open. This is the main problem. Try moving open, fopen and fclose out of the server loop.

You also opening for reading but fopening for writing, but I suppose it's just a typo. This combination will not run. You need to change the mode of fopen to "r".

There are other, smaller issues.

  1. You are not checking errors in the client. In your program the client will fail to open most of thee time, but sometimes open will succeed and write will fail.
  2. It makes little sense to use stdio for the pipe in this program. read and write would do just fine.

Last but not least, sleep is an indication of a design issue. Indeed, in this program blocking I/O would make more sense. It's OK to use sleep if you just want to experiment with non-blocking I/O, but in real programs it should be avoided.