I'm trying to open a fifo (named pipe) file, then write to it. I can't seem to make the server see what the "client" writes to it.
NOTE: I'm using terms like "client-server" for simplicity. I realize that they are actually just peers and that either side can close the pipe.
pipetest_server.c
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
int keep_going = 1;
static void signal_handler(int signum)
{
keep_going = 0;
}
int main()
{
int fd;
char *myfifo = "/tmp/mypipe";
char *line;
ssize_t amount_read;
ssize_t len;
FILE *f;
signal(SIGINT, signal_handler);
signal(SIGABRT, signal_handler);
signal(SIGTERM, signal_handler);
// make pipe
mkfifo(myfifo, 0666);
// open it
fd = open(myfifo, O_RDWR);
// make non-blocking
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
// make a file descriptor for pipe
f = fdopen(fd, "rw");
while(keep_going)
{
amount_read = getline(&line, &len, f);
if (amount_read > 0)
printf(line);
}
printf("quitting...\n");
close(fd);
unlink(myfifo);
return 0;
}
Then:
$ gcc pipetest_server.c
$ ./a.out
In another terminal:
$ ls -la /tmp/mypipe
prw-rw-r--. 1 myuser myuser 0 Nov 20 12:58 /tmp/mypipe
OK -- at this point, there is a pipe there. Now for the problems
1) Write to pipe with echo. Nothing happens
$ echo Hi >> /tmp/mypipe
<nothing comes out of the server>
2) Cat'ing the pipe, shows the data
$ cat /tmp/mypipe
Hi
<blinking cursor>
What's happening....
The server is never getting the data, but the pipe has the data in it.
3) When I close the server, the pipe goes away
<ctrl-C>
^Cquitting...
This tells me that the server did indeed create the pipe and has control over it.
4) I'd really like to create a another program to write to the pipe
Ultimately, I want to have another program that will write to this pipe and the two programs will communicate over it.
Note: There are other SO articles about this, but none that just get to the point.
UPDATE -- Working Code
Here is the final solution in case anyone comes after.
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
static volatile sig_atomic_t keep_going = 1;
static void signal_handler(int signum)
{
keep_going = 0;
}
int main()
{
int fd;
char *myfifo = "/tmp/mypipe";
char *line;
ssize_t amount_read;
ssize_t len;
FILE *f;
signal(SIGINT, signal_handler);
signal(SIGABRT, signal_handler);
signal(SIGTERM, signal_handler);
// make pipe
mkfifo(myfifo, 0666);
// open it
fd = open(myfifo, O_RDWR);
// make non-blocking
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
// make a file descriptor for pipe
f = fdopen(fd, "rw");
while(keep_going)
{
amount_read = getline(&line, &len, f);
if (amount_read > 0)
printf(line);
if (amount_read == -1)
{
clearerr(f);
}
}
printf("quitting...\n");
close(fd);
unlink(myfifo);
return 0;
}
The problem is that you've set the file descriptor to non-blocking, then opened a FILE *
on it with fdopen. Stdio FILE streams do not understand non-blocking I/O, so on your first getline
call the read will fail (with EWOULDBLOCK or EGAIN) and the FILE will go into error state, and getline will return -1. Once the FILE is in error state, every call will immediately return -1 without actually trying to read again.
If you want to actually use non-blocking mode, you need to call clearerr(f)
after getline returns -1. You should also be checking errno, to be sure the error is EWOULDBLOCK or EAGAIN -- if there's a real error it will be something else.