我正在嘗試編寫一個代碼,它可以分叉一個子進程並使用管道與它進行通信。我使用兩個管道 - 一個用於寫入,另一個用於讀取子流程的標準流。這是我到目前爲止有:使用兩個管道的雙向進程間通信
#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...
它卡在read_move
函數的調用getline
,等待輸入。但我不明白這是可能的,因爲我已經關閉了另一端。
我在做什麼錯?
編輯: 我改變了read_move
方法,並在dup2
調用後關閉子進程中的管道端點。
非常感謝您指出了這一點。它確實有7個文件描述符。但是,在我關閉了4個管道末端之後,ls/proc/PID/fd仍給我4個FD - 0 1 2 3. FD 3爲青色,其他爲紅色。這是什麼意思? – prvnsmpth
另外,關閉管道末端並不能完全解決問題 - 程序進入無限循環。子進程不斷地從管道的末端讀取同樣的東西 - 雖然我只寫了一次。 – prvnsmpth
這可能是因爲gnuchess不能很好地處理EOF。嘗試貓| gnuchess,然後按^ D - gnuchess只是忽略EOF而不是退出。如果你做了一個ls -l到/ proc/PID/fd,你會得到更多關於哪個fd連接到什麼的信息。 –