C++ – IPC: Using of named pipes in c++ between two programs

cipclinuxnamed-pipes

I'm trying to realise a IPC between two different programs running on the same machine (in my case its a CentOS7). To have just a kind of loose coupling I decided to use a named pipe for the IPC. Therefore I'm was playing with the following example and ran into different problems.

Creating and writing into the pipe:

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

using namespace std;

main()  {
 int fd;
 char * myfifo = new char [12];
 strcpy(myfifo, "./tmp/myfifo1");

 /* create the FIFO (named pipe) */
 mkfifo(myfifo, 0666);
 /* write "Hi" to the FIFO */
 fd = open("./tmp/myfifo1", O_WRONLY ); //open(myfifo, O_WRONLY | O_NONBLOCK);
 if (fd == -1) {
     perror("open");
     return EXIT_FAILURE;
 } 
 printf("File open\n");
 write(fd, "entry [1]", sizeof("entry [1]"));
 sleep(1);
 write(fd, "entry [2]", sizeof("entry [2]"));
 sleep(2);
 write(fd, "entry [3]", sizeof("entry [3]"));
 printf("Content written\n");
 close(fd);
 printf("Connection closed\n");
 /* remove the FIFO */
 unlink(myfifo);
 return 0;
}

Reading the pipe:

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

using namespace std;

main()  {
 int fd; 
 fd_set set_a;

 char * myfifo = new char [12];
 strcpy(myfifo, "./tmp/myfifo1");
 char buffer[1024];

 fd = open("./tmp/myfifo1", O_RDONLY | O_NONBLOCK);
 if (fd == -1) {
     perror("open");
     return EXIT_FAILURE;
 } 
 ssize_t bytes;
 size_t total_bytes = 0;
 printf("\nDropped into read pipe\n");
 while(1){
     if((bytes = read(fd, buffer, sizeof(buffer))) > 0){
         std::string message(&buffer[22]);
         total_bytes += (size_t)bytes;
         printf("%i", bytes);

         printf("Message: %s\n", message.c_str());
         memset(&buffer[0], 0, sizeof(buffer));
     }else{
         if (errno == EWOULDBLOCK) {
             printf("\ndone reading (%d bytes)\n", (int)total_bytes);
             //break;
         }
         printf("No message\n");
         sleep(2);
     } 
 }
 return EXIT_SUCCESS;
}

I feel like named pipes are pretty unflexible in its behavior I figured out with my test programs. First of all if no reading process is attached to the fifo pipe all messages except of the last one written to the pipe get lost (or generally speaking only the last message can be read after the reading process is attached to the pipe). If you write multiple messages into the pipe all messages betweem the reading (e.g. polled) will be interpreted as one single message (I'm aware that they can be splitted by \0).

The main goals for the named pipe is a) system logs and b) kind of user authentication. The asynchronous of named pipes fits perfectly to my need. But anyway, I'm not sure if named pipes are the best solution for IPC between different programs. Also I'm not sure if the behavior descripted above is normal or if I'm using named pipe in a wrong way. I also thought about sockets but then I will run into huge blocking problems.

Thanks for your help.

Best Answer

"First of all if no reading process is attached to the fifo pipe all messages except of the last one written to the pipe get lost".

No, they don't. Use cat instead of your (lousily written :D) reading process and you'll get all of the messages.

You are right. Pipes are byte-oriented, not message oriented. If you want messages, there's other IPC for that (e.g., SysV message queues).

Beej's Guide to Unix IPC is an excellent intro to Unix ipc, if you want something more advanced, then Advanced Programming in the Unix Environment by Richard Stevens is very good.

As far as user authentication is concerned, check out Unix sockets.