Weird behaviour of fifos on linux

2019-06-11 15:45发布

问题:

I'm studying linux fifos and I made two small C programs which communicate through fifo. The first one acts like a server, it receive a pattern and executes a command using that pattern. The second one acts like a client, it sends the pattern and receive the result. I want the server to be capable of serving multiple requests, not necessarily simultaneously, but the weird thing is that after the first client is served it just stops although I put there an infinite loop.

server.c

#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>


void siginthandler(int i){
    remove("./fifo1");
    remove("./fifo2");
    printf("Got SIGINT signal\n");
    exit(EXIT_SUCCESS);
}


int main(int argc, char *argv[]){
    signal(SIGINT, siginthandler);
    int f = mkfifo("./fifo1", 0600);
    if (f == -1){
        perror("Unable to create fifo1\n");
        exit(EXIT_FAILURE);
    }
    f = mkfifo("./fifo2", 0600);
    if (f == -1){
        perror("Unable to create fifo2\n");
        exit(EXIT_FAILURE);
    }
    int fd1 = open("./fifo1", O_RDONLY);
    int fd2 = open("./fifo2", O_WRONLY);
    if (fd1 == -1 || fd2 == -1){
        perror("Unable to open fifos\n");
        exit(EXIT_FAILURE);
    }
    while (1){
        char buf[50];
        char pattern[50];
        read(fd1, pattern, 50);
        char command[80] = "ps -e | grep ";
        strcat(command, pattern);
        FILE *result = popen(command, "r");
        while (fgets(buf, 50, result)){
            write(fd2, buf, 50);
            //printf("%s", buf);
        }
        memset((void *) buf, 0, 50);
        write(fd2, buf, 50);
        pclose(result);
    }
    remove("./fifo1");
    remove("./fifo2");
    return 0;
}

client.c

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

int main(int argc, char *argv[]){
    int fd1 = open("./fifo1", O_WRONLY);
    int fd2 = open("./fifo2", O_RDONLY);
    if ((fd1 == -1) || (fd2 == -1)){
        perror("Unable to find fifos");
        exit(EXIT_FAILURE);
    }
    char input[50];
    printf("Give pattern: ");
    scanf("%s", input);
    write(fd1, input, 50);
    char buf[50];
    while (read(fd2, buf, 50) == 50){
        if (buf[0] == 0){
            break;
        }
        printf("%s", buf);
    }
    return 0;
}

回答1:

When the first client closes the FIFO, the server gets EOF on the FIFO, and continues to get no new data in perpetuity. The server has to reopen the FIFO for the next client. If there were multiple clients all with the FIFO open concurrently, the server would not get EOF until the last of the clients disconnected (as long as there is one writer, the reader — the server — will be OK).

This is expected behaviour — or, since you weren't expecting it, is the behaviour that should be expected.

Of course, since your code completely ignores the return value from read(), you have no idea what, if anything, is being read.

The code:

memset((void *) buf, 0, 50);
write(fd2, buf, 50);

is curious; why would you send a buffer of 50 0 bytes to the client? You could perfectly well close the FIFO without sending that.

Also note that writing on a FIFO where there isn't a reader will generate a SIGPIPE signal — and you aren't handling those. The default action for SIGPIPE is to exit.



回答2:

Writing to a pipe gets you a SIGPIPE if there's no reader; you need to have the server open the pipe for reading, so there is a reader (which doesn't read anything, but it exists).



标签: c linux fifo