0

My server and client are communicating back and forth using two named pipes (fifo) in C until the server receives an exit message. Apparently the server side blocks the second time it tries to read() from its FIFO despite the client writing to it successfully. I think the problem is that the server tries to read() sooner than the client could write() to it.

Here is the server:

#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "header.h"
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>

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

        //fifo for the server to read from
        if (mkfifo(FIFONAME, S_IFIFO|0666) < 0) {
                if (errno != EEXIST) {
                        perror("Error with mkfifo");
                        exit(1);
                }
        }

        int f;
        if ((f = open(FIFONAME, O_RDONLY)) < 0) {
                perror("Error with open");
                exit(1);
        }

        Message msg;

        while(1) {
                if ((read(f, &msg, sizeof(Message))) > 0) {
                        if (strcmp(msg.user, "exit") == 0) {
                                close(f);
                                unlink(FIFONAME);
                                exit(0);
                        }
                        if (strcmp(msg.user, "new client") == 0) {
                        switch (fork()) {
                                case -1:{
                                        perror("Error with fork");
                                        exit(1);
                                        }
                                case 0:{
                                        char gender[MAXLEN];
                                        char client_fifo[30];
                                        sprintf(msg.user, "I need client's gender\n");
                                        sprintf(client_fifo, "fifo_%d", msg.pid);
                                        msg.pid = getpid();
                                        int o;
                                        //open client's fifo for server to write to
                                        if ((o = open(client_fifo, O_WRONLY)) == -1) {
                                                        perror("Error opening client fifo");
                                                        exit(1);
                                                        }
                                        //send message
                                        write(o, &msg, sizeof(Message));
                                        //read client's answer, but program blocks here
                                        if ((read(f, &msg, sizeof(Message))) > 0) {
                                                sprintf(gender,"%s", msg.user);
                                                printf("Client's gender is %s\n", gender);
                                        }

                                        close(o);
                                        exit(0);
                                       }
                        }
                        }
                }
        }

        return 0;
}

The client code:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include "header.h"
#include <unistd.h>

int f,fc;
char fifoname[20];
Message msg;

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

        sprintf(fifoname, "fifo_%d", getpid());
        if (mkfifo(fifoname, S_IFIFO | 0666) < 0) {
                perror("Error with client's fifo");
                printf("Could not create fifo_%d", getpid());
                exit(1);
        }
        if ((f=open(FIFONAME,O_WRONLY))<0) {
                perror("Error connecting to server");
                exit(2);
        }

        char gender[MAXLEN];
        strcpy(msg.user, "new client");
        msg.pid = getpid();
        //first message to server
        write(f, &msg, sizeof(msg));

        char arg[MAXLEN];
        if (argc > 1) {
                strcpy(arg, argv[1]);
        } else {
                strcpy(arg, "work");
        }
        if (strcmp(arg, "exit")) {

                if ((fc = open(fifoname, O_RDONLY))<0) {
                        perror("Error opening client's fifo");
                        printf("Could not open my fifo");
                        exit(3);
                }
                if (read(fc, &msg, sizeof(msg)) > 0) {
                        printf("%s\n",msg.user);
                }
                scanf("%s", gender);
                strcpy(msg.user, gender);
                msg.pid = getpid();
                printf("writing gender...\n");
                write(f, &msg, sizeof(msg));
                //program successfully reaches this print:
                printf("gender written\n");
                close(fc);
        }
        unlink(fifoname);
        close(f);
        exit(0);
}

And the header containing the struct for the message:

#define MAXLEN 20
typedef struct {
    int pid;
    char user[MAXLEN];
} Message;

#define FIFONAME "fifo_server"

I need to write further back and forth messages like this but I don't know how to get the server not to block on the second call of read()

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
Lois2B
  • 111
  • 1
  • 16
  • You have competing `read` calls in the server in both the parent and the child processes. After `fork`, both processes will race to the `read` call to get the data. Whichever runs first after the client writes will win and the other process will block. – kaylum May 24 '21 at 11:58
  • @kaylum I need to fork so that every client connecting to the server would be served parallel in a different process. The ```read``` after ```fork``` should only be seen by the child process, that's why I use cases. – Lois2B May 24 '21 at 12:02
  • Did you understand my first comment? Both parent and child processes call `read` so they will fight for the same data. There is only one fifo and reading it from one process will cause the other process to not get the data and thus block. – kaylum May 24 '21 at 12:06
  • 1
    "The read after `fork`" is an ambiguous phrase, since there is more than one read after the fork. After the fork, there are 2 processes executing, one of which is in a while loop that starts with a `read`, and that `read` occurs after the fork. Have the parent wait. – William Pursell May 24 '21 at 12:14

0 Answers0