9

I've been trying to wrap my head around FIFO, and came up with a simple program of server and client.
I'm not trying to do anything fancy, just to have one process that will play a role of 'server', this process will 'listen' to any messages delivered by another process; the client.
Here's what I wrote:

server.c

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


#define INGOING "clientToServer.fifo"

#define BUFFER 200

int main(int argc, char *argv[]) {

    char in[BUFFER];

    mkfifo(INGOING, 0666);

    printf("Welcome to server.\n");
    printf("channel for sending messages to server is %s\n", INGOING);

    int in_fd=open(INGOING, O_RDONLY);

    if (in_fd==-1) {
        perror("open error");
        exit(-1);
    }

    while (read(in_fd, in, BUFFER)>0) {
        printf("You sent %s to server.\n", in);
    }

    return 2;
}

As you can see, this is pretty straight forward, when I ran this at background with ./server.out& it's blocked at the read call and waiting for anyone to write to clientToServer.fifo. so far so good.

Now, consider the client end:
client.c

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


#define BUFFER 200

int main(int argc, char *argv[]) {

    char input[BUFFER]={0};
    int out_fd=open("clientToServer.fifo", O_WRONLY);

    if (out_fd==-1) {
        perror("open error");
    }

    while (1) {

        printf("What would you like to send to server? (send Quit to quit)\n");
        fgets(input, BUFFER, stdin);
        if (input[strlen(input)-1]=='\n') {
            input[strlen(input)-1]='\0';
        }

        if (strcmp(input, "Quit")==0) {
            printf("Bye!");
            break;
        }

        if (write(out_fd, input, strlen(input))==-1) {
            perror("write error");
        }
    }

    return 1;
}

This is the client. also pretty simple code. when I run it with ./a.out from shell, it works - it sends the message, and the server.out process prints You sent %s to server.
Problem is, when I send Quit through the client to the server, although the a.out process terminates as desired, the while loop in the server.out breaks as well. meaning, the read no longer blocks the server.out process and awaits other clients, instead, the server program ends, along with the client.
Why is this happening? shouldn't the read suspend the server.out again, even after the a.out process ends?

Newton Falls
  • 2,148
  • 3
  • 17
  • 22
so.very.tired
  • 2,958
  • 4
  • 41
  • 69
  • You have undefined behavior in your code: You send the string from the client without the terminator, and read it without adding the adding the terminator, which means the `printf` in the server will print an unterminated string. – Some programmer dude May 02 '14 at 17:43
  • @JoachimPileborg, so: `write(out_fd, input, strlen(input)+1)` ? – so.very.tired May 02 '14 at 17:54
  • No: `int nbytes; while ((nbytes = read(in_fd, in, sizeof(in))) > 0) printf("You sent [%.*s] to the server\n", nbytes, in);` where the square brackets delimit the data that was sent (and are therefore optional). – Jonathan Leffler May 02 '14 at 21:04
  • Hi! And thank you so much for saying this in your question `I ran this at background with ./server.out& it's blocked at the read call and waiting for anyone to write to clientToServer.fifo`. This helped me realize something, thus I solved my problem. It was somnething related to FIFO. I really like this site and people who put in the elbow grease! Keep it up! – M.Ionut May 20 '20 at 19:54

2 Answers2

11

when I ran this at background with ./server.out& it's blocked at the read call and waiting for anyone to write to clientToServer.fifo

Actually it blocks at the open. This is the way FIFOs work. The open (in blocking mode) is going to block until something opens the FIFO on the other end.

the while loop in the server.out breaks as well. meaning, the read no longer blocks the server.out process and awaits other clients, instead, the server program ends

Again, this is normal behavior. Only one client process is connected to the FIFO so when it closes its end then EOF is sent and the server quits. If multiple clients are attached to the FIFO at the same time you won't see EOF until the last client closes it. If you want a long running server to serve multiple clients continuously the easiest way to accomplish it is to open the server's FIFO as read/write. This way there is always a reader/writer - the server itself - and you won't see EOF when even the last client exits. When it is time to shut down the server then close the appropriate end in the server and let nature take its course as the real clients quit.

Duck
  • 26,924
  • 5
  • 64
  • 92
  • Thanks. Where can I find a manual that explains all of this in detail? I couldn't find it in the linux manual... – so.very.tired May 02 '14 at 22:24
  • 1
    I'm not sure there is a manual per se for any of this stuff. There is no replacement for a good, detailed unix book and iterative close reading of the man pages. There is a lot of source material of varying quality all over the web. One that seems to be highly regarded is [Beej's Guides](http://beej.us/guide/bgipc/output/html/multipage/index.html) – Duck May 02 '14 at 23:02
  • It seems like exactly what I need! :-) – so.very.tired May 03 '14 at 08:46
3

When the client exits it closes the pipe connection, which causes the read function in the server to return 0 which exits the loop.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Why did it stop the process at `read` when I ran `server.out` initially? there wasn't any open pipe connections before running `a.out`. – so.very.tired May 02 '14 at 17:56