Двунаправленное межпроцессное взаимодействие с использованием двух каналов
Я пытаюсь написать код, который разветвляется на подпроцесс и взаимодействует с ним с помощью каналов. Я использую два канала - один для записи, а другой для чтения из стандартных потоков подпроцесса. Вот что у меня так далеко:
#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 (), поэтому один из стандартных дескрипторы заменяются на трубу случайно. Но я думаю, что здесь дело не в этом.)