我的目标是将某些流程执行的会话保存到json(像[{ type: 'stdout', data: 'What's your name?' }, { type: 'stdin', data: 'Alex.' }, { type: 'stdout', data: 'Hi, Alex!' }]
这样的smth)。我决定用nodejs做这件事,但我遇到了一些问题。产生进程的stdout在管道和继承时的工作方式不同。所以,例如我将这个C代码(简单的猜数游戏)编译成main
:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
int random_num = 0;
int guessed_num = 0;
int counter = 0;
srand(time(NULL));
random_num = rand() % 10 + 1;
printf("Guess my number! ");
while(1) {
counter++;
scanf("%d", &guessed_num);
if (guessed_num == random_num) {
printf("You guessed correctly in %d tries! Congratulations!\n", counter);
break;
}
if (guessed_num < random_num)
printf("Your guess is too low. Guess again. ");
if (guessed_num > random_num)
printf("Your guess is too high. Guess again. ");
}
return 0;
}
这个JavaScript代码:
var spawn = require('child_process').spawn;
var child = spawn('./main', { stdio: 'inherited' });
执行此JavaScript代码的结果将是:
Guess my number! 1
Your guess is too low. Guess again. 2
Your guess is too low. Guess again. 3
You guessed correctly in 3 tries! Congratulations!
但是,当stdio
为inherited
时,我无法附加到任何流程流并将数据保存到json。所以我尝试了这个:
var spawn = require('child_process').spawn;
var child = spawn('./main', { stdio: 'pipe' });
child.stdout.on('data', function(data) { process.stdout.write(data) });
process.stdin.on('data', function(data) { child.stdin.write(data) });
由于执行而得到这个:
1
2
3
Guess my number! Your guess is too low. Guess again. Your guess is too low. Guess again. You guessed correctly in 3 tries! Congratulations!
当子进程正在等待输入时,子进程的stdout以某种方式挂起。可能它必须对事件循环做一些事情,但我不确定。无论如何,inherited
和pipe
的行为是非常不同的,似乎是错误的......
我该怎么办?也许有一些解决方法?
答案 0 :(得分:2)
在inherited
模式下,C程序继承了绑定到终端的描述符。终端是一个交互设备,它自动将printf()
函数的缓冲设置为stdout
进行行缓冲(即遇到新行时刷新缓冲区)。
OTOH,在pipe
模式下,libc不检测交互设备,并切换到完全缓冲(即缓冲区仅在其满或调用fflush()
时刷新。
解决方法是在每次fflush(stdout)
来电后致电printf()
,或者为stdout
全部禁用缓冲:setvbuf(stdout, NULL, _IONBF, 0);
。
有关管道与终端缓冲的完整说明,请参阅此answer,包括确定stdout
缓冲的libc示例。