Двунаправленное межпроцессное взаимодействие с использованием двух каналов

Я пытаюсь написать код, который разветвляется на подпроцесс и взаимодействует с ним с помощью каналов. Я использую два канала - один для записи, а другой для чтения из стандартных потоков подпроцесса. Вот что у меня так далеко:

#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;
}

Выход вышеуказанной программы

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

Это застревает на getline позвонить в read_move функция, ожидающая ввода. Но я не понимаю, как это возможно, так как я закрыл другой конец.

Что я делаю неправильно?

РЕДАКТИРОВАТЬ: я изменил read_move метод и закрытые концы трубы в дочернем процессе после dup2 звонки.

1 ответ

Решение

Вы не закрываете wpipe в дочернем процессе. Таким образом, вы фактически передаете 7 файловых дескрипторов шахматам gnu при запуске - dup'ed stdin, stdout и stderr; 2 дескриптора в wpipe и 2 дескриптора в rpipe.

Если вы работаете в Linux, узнайте идентификатор процесса в шахматах gnu во время работы вашей программы и выполните команду ls /proc//fd, чтобы увидеть все ее файловые дескрипторы.

Как только вы добавите

близко (wpipe[0]); закрыть (wpipe[1]); близко (rpipe[0]); закрыть (rpipe[1]);

между dup2() и execl() все должно быть в порядке.

(Это по-прежнему исключает обработку ошибок, как в случае сбоя одного из dup2(), или, что еще хуже, ваша программа закрыла один из fds [0, 1, 2] перед вызовом pipe (), поэтому один из стандартных дескрипторы заменяются на трубу случайно. Но я думаю, что здесь дело не в этом.)

Другие вопросы по тегам