2013-12-12 6 views
1

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

#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, ожидая ввода. Но я не понимаю, как это возможно, так как я закрыл другой конец.

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

EDIT: Я изменил метод read_move и закрыл концы труб в дочернем процессе после вызовов dup2.

ответ

2

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

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

После добавления

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

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

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

+0

Большое спасибо за указание на это. В нем было 7 дескрипторов файлов. Однако после того, как я закрыл 4 концы труб, ls/proc/PID/fd все равно дали мне 4 FDs - 0 1 2 3. FD 3 был голубым, остальные - красным. Что это значит? – prvnsmpth

+0

Кроме того, закрытие концов труб не полностью решает проблему - программа переходит в бесконечный цикл. Детский процесс продолжает читать одно и то же снова и снова с конца своего канала, хотя я его пишу только один раз. – prvnsmpth

+0

Возможно, это связано с тем, что gnuchess не справляется с EOF. Попробуйте кошку | gnuchess, затем нажмите^D - gnuchess просто игнорирует EOF вместо выхода. Если вы выполните ls -l to/proc/PID/fd, вы получите больше информации о том, к какому fd подключен. –

Смежные вопросы