我正在尝试编写一个分叉子进程并使用管道与它通信的代码。我使用两个管道 - 一个用于写入,另一个用于从子流程的标准流中读取。这是我到目前为止所做的:
#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
方法并关闭了子进程中的管道端。
答案 0 :(得分:2)
您没有在子进程中关闭wpipe。所以当你启动它时,你实际上是将7个文件描述符传递给gnu国际象棋 - dup'ed stdin,stdout和stderr; wpipe中的2个描述符,以及rpipe中的2个描述符。
如果您使用的是linux,请在程序运行时找出gnu chess的进程ID,然后执行ls / proc // fd查看其所有文件描述符。
添加
后接近(wpipe [0]); 关闭(wpipe [1]); 关闭(RPIPE [0]); 关闭(RPIPE [1]);
在dup2()和execl()之间的,你应该没问题。
(这仍然省略了错误处理,就像其中一个dup2()失败,或者更糟糕的是,你的程序在调用pipe()之前关闭了其中一个fds [0,1,2]所以标准描述符被意外地替换为管道。但我想这不是重点。)