I'm following THIS TutorialsPoint guide to Linux Piping, and I specifically need to use FIFOs.
However, the code doesn't work at all for the server side.
The server file either hangs indefinitely or it reads nothing, while the client instead writes on the FIFO and immediately reads it has just written.
Here's the full code for both files in case you don't want to go through TutorialsPoint:
fifoserver_twoway.cpp
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
void reverse_string(char *);
int main() {
int fd;
char readbuf[80];
char end[10];
int to_end;
int read_bytes;
/* Create the FIFO if it does not exist */
mkfifo(FIFO_FILE, S_IFIFO|0640);
strcpy(end, "end");
fd = open(FIFO_FILE, O_RDWR);
while(1) {
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOSERVER: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
to_end = strcmp(readbuf, end);
if (to_end == 0) {
close(fd);
break;
}
reverse_string(readbuf);
printf("FIFOSERVER: Sending Reversed String: \"%s\" and length is %d\n", readbuf, (int) strlen(readbuf));
write(fd, readbuf, strlen(readbuf));
/*
sleep - This is to make sure other process reads this, otherwise this
process would retrieve the message
*/
sleep(2);
}
return 0;
}
void reverse_string(char *str) {
int last, limit, first;
char temp;
last = strlen(str) - 1;
limit = last/2;
first = 0;
while (first < last) {
temp = str[first];
str[first] = str[last];
str[last] = temp;
first++;
last--;
}
return;
}
fifoclient_twoway.cpp
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
int main() {
int fd;
int end_process;
int stringlen;
int read_bytes;
char readbuf[80];
char end_str[5];
printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n");
fd = open(FIFO_FILE, O_CREAT|O_RDWR);
strcpy(end_str, "end");
while (1) {
printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
end_process = strcmp(readbuf, end_str);
//printf("end_process is %d\n", end_process);
if (end_process != 0) {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOCLIENT: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
} else {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
close(fd);
break;
}
}
return 0;
}
When I run both processes, this is what I get:
./fifoserver_twoway
FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0
FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0
./fifoclient_twoway
FIFOCLIENT: Sent string: "ciao" and string length is 4
FIFOCLIENT: Received string: "ciao" and length is 4
Enter string: why won't you reverse?
FIFOCLIENT: Sent string: "why won't you reverse?" and string length is 29
FIFOCLIENT: Received string: "why won't you reverse?" and length is 29
It's also worth noting that before starting to write this question, the server behaviour was completely different: instead of receiving nothing and printing like you see here, it would hang indefinitely after the "read" (and I haven't changed the code one bit, except for changing the FIFO_FILE path)
You let the server sleep after writing – but not the client. That way, the client still might read its own output back before the server can fetch it. So at very least you should add a sleep after both writes, letting the server sleep a bit longer to make sure the client wakes up first to read the servers output.
Accessing the same end of unnamed pipes (created via pipe functions) concurrently is undefined behaviour. While not sure for named pipes, I'd assume pretty much the same there as well. Synchronising concurrent access to such ends via simple delays (sleep
, usleep
) might perhaps do the trick, but it is a pretty unsafe method.
I'd rather recommend two separate pipes instead (as Tony Tannous proposed already), one for each direction (open the respective ends RDONLY
or WRONLY
as needed), then you get full duplex communication instead of half duplex and you don't need further synchronisation either (delays in most simple variant):
// server
int fd_cs = open(FIFO_FILE_CS, O_RDONLY);
int fd_sc = open(FIFO_FILE_SC, O_WRONLY);
read(fd_cs, ...);
write(fd_sc, ...);
// client
int fd_cs = open(FIFO_FILE_CS, O_WRONLY);
int fd_sc = open(FIFO_FILE_SC, O_RDONLY);
write(fd_cs, ...);
read(fd_sc, ...);