0

I am trying to write two programs that will communicate via FIFOs in C. I am experimenting with FIFOs for an assignment I have.

When I know the number of messages and read them with a for loop, it prints out all the messages that were sent from the other side. If I use a while loop, it only sends two of them. The code is slightly changed from this question How to send a simple string between two programs using pipes?

This works:

/* writer */
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int fd;
    char * myfifo = "/tmp/myfifo";

    /* create the FIFO (named pipe) */


    /* write "Hi" to the FIFO */
    fd = open(myfifo, O_WRONLY);
    int i;
    for(i = 0; i < 10; i++)
         write(fd, "Hi", sizeof("Hi"));
    close(fd);



    return 0;
}

And: (edited)

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

#define MAX_BUF 1024

int main()
{
    int fd;
    char * myfifo = "/tmp/myfifo";
    char buf[MAX_BUF];

     mkfifo(myfifo, 0666);
    /* open, read, and display the message from the FIFO */
    fd = open(myfifo, O_RDONLY);
    int i;
    for(i = 0; i < 10; i++)
    {
        int n = read(fd, buf, MAX_BUF);
        printf("n = %d , Received: %s\n",n, buf);
    }
    close(fd);

     /* remove the FIFO */
    unlink(myfifo);

    return 0;
}

Edit: This now prints

n = 18 , Received: Hi
n = 12 , Received: Hi
n = 0 , Received: Hi
n = 0 , Received: Hi
n = 0 , Received: Hi
n = 0 , Received: Hi
n = 0 , Received: Hi
n = 0 , Received: Hi
n = 0 , Received: Hi
n = 0 , Received: Hi

When I change the reader to this, it doesn't work:

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

#define MAX_BUF 1024

int main()
{
    int fd;
    char * myfifo = "/tmp/myfifo";
    char buf[MAX_BUF];

     mkfifo(myfifo, 0666);
    /* open, read, and display the message from the FIFO */
    fd = open(myfifo, O_RDONLY);
    int i;
    while(read(fd, buf, MAX_BUF))
        printf("Received: %s\n", buf);

    close(fd);

     /* remove the FIFO */
    unlink(myfifo);

    return 0;
}

I am running the two programs in two separate terminals and all. When I run them with the second reader, it only prints out:

Received: Hi
Received: Hi

Any help would be appreciated.

Community
  • 1
  • 1
Theo Stefou
  • 389
  • 2
  • 16
  • 2
    how do you know the first version works if you don't check for the result of `read()`? If it doesn't read anything `buf` will keep it's previous contents – Ingo Leonhardt Apr 25 '17 at 12:15
  • @IngoLeonhardt You are right. Just edited the answer and it prints out 0 as the return value all the time. Do you have any suggestion on how I should do this? – Theo Stefou Apr 25 '17 at 12:21

2 Answers2

2

Pipes are stream based, not message based. While the number of bytes read should match the number written, the number of read calls is not necessarily the same as the number of write calls.

If we modify the reader to print the number of bytes received:

int len;
while((len=read(fd, buf, MAX_BUF)) > 0) {
    printf("Received %d: %s\n", len, buf);
}

I get the following output:

Received 30: Hi

So in the second case, there are 10 writes of 3 bytes (2 for the letters H and i and one for the null terminating byte) and 1 read of 30 bytes. The reason 3 bytes is being written on each write call is because the string constant "Hi" has type char [3].

You only see one instance of "Hi" printed because the third byte is a null byte which terminates the string, so nothing past that is printed.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • I see, I noticed that too while I was experimenting, but I still don't know what the best way to have them communicate constantly is. – Theo Stefou Apr 25 '17 at 12:31
  • I accept this answer. because it made me realize that I shouldn't be writing nulls inside the pipe because it messes up the other end. I changed the code to "sizeof("Hi")-1" and it now prints a bunch of Hi's.Thanks. – Theo Stefou Apr 25 '17 at 12:37
0

In the second version, continued execution of the loop depends on the value returned by read(), whereas in the first version it loops ten times unconditionally.

And since it doesn't clear the buffer, as long as the first iteration reads 'Hi', all subsequent iterations will print 'Hi' regardless of the success, partial success, or failure of the read().

Jeremy
  • 5,055
  • 1
  • 28
  • 44
  • As the output in your edit shows, all of the data from the ten writes is being read in the first two reads. – Jeremy Apr 25 '17 at 12:23