Frage

I am trying to write code that forks a subprocess and communicates with it using pipes. I am using two pipes - one for writing to, and the other for reading from the standard streams of the subprocess. Here's what I have so far:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

void read_move(int fd)
{
    FILE *stream = fdopen(fd, "r");
    char c;
    setvbuf(stream, NULL, _IONBF, BUFSIZ);  
    while ((c = fgetc(stream)) != EOF)
    {
        putchar(c);
    }
    fclose(stream);
}

void write_move(int fd, const char *move)
{
    FILE *stream = fdopen(fd, "w");
    setvbuf(stream, NULL, _IONBF, BUFSIZ);
    fprintf(stream, "%s", move);
    fclose(stream);
}

int main() {
    pid_t pid;
    int wpipe[2];
    int rpipe[2];
    if (pipe(wpipe) || pipe(rpipe))
    {
        fprintf(stderr, "Pipe creation failed.\n");
        return EXIT_FAILURE;
    }
    pid = fork();
    if (pid == 0)
    {
        /* gnuchess process */
        setvbuf(stdin, NULL, _IONBF, BUFSIZ);
        setvbuf(stdout, NULL, _IONBF, BUFSIZ);
        setvbuf(stderr, NULL, _IONBF, BUFSIZ);
        dup2(wpipe[0], STDIN_FILENO);
        dup2(rpipe[1], STDOUT_FILENO);
        dup2(rpipe[1], STDERR_FILENO);
        close(wpipe[0]);
        close(wpipe[1]);
        close(rpipe[0]);
        close(rpipe[1]);
        if (execl("/usr/games/gnuchess", "gnuchess", "-x", NULL) == -1)
        {
            fprintf(stderr, "Exec failed.\n");
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }

    /* parent process */

    printf("Sending move to GNU Chess... \n");
    close(wpipe[0]); /* Close other end */
    write_move(wpipe[1], "c3\n");   

    printf("Reading response... \n");
    close(rpipe[1]); /* Close other end */
    read_move(rpipe[0]);

    /* clean up */  
    close(wpipe[1]);
    close(rpipe[0]);    

    /* kill gnuchess */
    kill(pid, SIGTERM);

    return EXIT_SUCCESS;
}

The output of the above program is

Sending move to GNU Chess... 
Reading response... 

It gets stuck at the getline call in the read_move function, waiting for input. But I don't understand how that's possible, since I have closed the other end.

What am I doing wrong?

EDIT: I changed the read_move method and closed the pipe ends in the child process after the dup2 calls.

War es hilfreich?

Lösung

You're not closing wpipe in the child process. So you're actually passing 7 file descriptors to gnu chess when you start it - the dup'ed stdin, stdout and stderr; the 2 descriptors in wpipe, and the 2 descriptors in rpipe.

If you're on linux, find out the process id of gnu chess while your program is running, and do a ls /proc//fd to see all its file descriptors.

Once you add

close(wpipe[0]); close(wpipe[1]); close(rpipe[0]); close(rpipe[1]);

between the dup2()s and the execl(), you should be ok.

(This still omits error handling, like the case that one of the dup2()s fails, or, even worse, your program has closed one of the fds [0, 1, 2] before calling pipe() so one of the standard descriptors gets replaced with a pipe accidentially. But i guess that's not the point here.)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top