我正在编写代码以与另一个程序进行交互。
FILE* streamout = fdopen(fdout[0],"r");
我使用了fdopen之前显示的功能,以便能够像读取文件一样处理读取。 问题是我不知道在以下循环中尝试从streamout读取时要使用什么停止条件。
while(fgets(endbuffer,sizeof(endbuffer),streamout) != NULL)
{
strcat(buffer,endbuffer);
}
即使流式传输完成,程序也永远不会退出while循环。
修改
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
//this function returns when it receives a particular response ie: imready
void wait_until_ready(FILE *,FILE *);
int main(){
int fdin[2];
int fdout[2];
pid_t pid;
if ((pipe(fdin)<0)||(pipe(fdout)<0))
{
perror("pipe error");
exit(1);
}
if ((pid = fork())<0)
{
perror("fork error");
exit(2);
}
if (pid == 0)
{
close(fdin[1]);
close(fdout[0]);
dup2(fdin[0],0);
dup2(fdout[1],1);
execlp("stockfish","stockfish",0);
}
else
{
close(fdin[0]);
close(fdout[1]);
FILE* streamin = fdopen(fdin[1],"w");
FILE* streamout = fdopen(fdout[0],"r");
char buffer[1024];
wait_until_ready(streamin,streamout);
fprintf(streamin,"position startpos\n");
fprintf(streamin,"go\n");
fflush(streamin);
while (fgets(endbuffer,sizeof(endbuffer),streamout) != NULL)
{
strcat(buffer,endbuffer);
}
}
return 0;
}
答案 0 :(得分:0)
我引用了经验法则(引用自己,AFAIK):
dup()
或dup2()
- 或fcntl()
如果你是受虐狂 - 要将管道的一端复制到标准输入或标准输出,你应该关闭 原始管道的两个 两端(1×pipe()
,1×dup2()
⇒2×close()
)。你声称你这样做。您的代码显示您没有。你有:
if (pid == 0)
{
close(fdin[1]);
close(fdout[0]);
dup2(fdin[0],0);
dup2(fdout[1],1);
execlp("stockfish","stockfish",0);
}
你需要:
if (pid == 0)
{
dup2(fdin[0],0);
dup2(fdout[1],1);
close(fdin[0]);
close(fdin[1]);
close(fdout[0]);
close(fdout[1]);
execlp("stockfish","stockfish",0);
fprintf(stderr, "Failed to execute 'stockfish'\n");
exit(EXIT_FAILURE);
}
如果你不这样做,你可能会遇到问题。如果你小心(原来的两个dup2()
电话很好,你可以在close()
电话之前完成一些关闭,但我将所有四个电话组合在一起修改后的版本中。如果您在close()
次呼叫后同时执行这两项操作,则可以对操作进行相当大的重新排序,以确定哪个dup2()
首先出现,哪一次出现在哪一对中。在执行任何操作之前,您可以在一个管道上执行所有操作。等
请注意,如果execlp()
失败,您应确保退出 - 或采取其他适当的规避措施。它迟早会发生,通常会导致麻烦。有些人会争辩_exit()
而不是exit()
。如果您在fork()
之前刷新了待处理的I / O,则应该没有问题。
乍一看,父代码看起来还不错。您没有将dup2()
用于标准输入或标准输出,因此只关闭管道的两个未使用的端是可以的。
你给孩子写了一条信息。你......哦,你没有关闭孩子的管道(fclose(streamin);
)...所以你把信息写给孩子,然后你得到一个回复,但孩子现在正在等待下一个命令父级,而父级正在等待来自子级的更多数据。所以他们处于僵局 - 两个进程都在等待对方做某事,而且也不会做对方需要的事情,所以他们陷入了僵局。
如果您要将单个邮件写入stockfish
,则需要在进入读取循环之前调用fclose(streamin);
。如果您需要发送更多消息,您必须知道如何判断stockfish
已完成当前消息,以便您可以中断循环并返回发送下一个命令。这可能是imready
函数所需的另一行wait_until_ready()
。所以你可能需要:
buffer[0] = '\0'; // Make sure that strcat() works sanely
while (fgets(endbuffer, sizeof(endbuffer), streamout) != NULL)
{
if (strcmp(endbuffer, "imready\n") == 0)
break;
// check for buffer overflow, etc before blithely appending!
// this is not efficient; it is sufficient, though.
if (strlen(buffer) + strlen(endbuffer) + 1 >= sizeof(buffer))
break;
strcat(buffer, endbuffer);
}