当被管道传送时,产生的进程的stdout很奇怪

时间:2016-05-15 00:14:33

标签: javascript c node.js unix

我的目标是将某些流程执行的会话保存到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!

但是,当stdioinherited时,我无法附加到任何流程流并将数据保存到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以某种方式挂起。可能它必须对事件循环做一些事情,但我不确定。无论如何,inheritedpipe的行为是非常不同的,似乎是错误的......

我该怎么办?也许有一些解决方法?

1 个答案:

答案 0 :(得分:2)

inherited模式下,C程序继承了绑定到终端的描述符。终端是一个交互设备,它自动将printf()函数的缓冲设置为stdout进行行缓冲(即遇到新行时刷新缓冲区)。

OTOH,在pipe模式下,libc不检测交互设备,并切换到完全缓冲(即缓冲区仅在其满或调用fflush()时刷新。

解决方法是在每次fflush(stdout)来电后致电printf(),或者为stdout全部禁用缓冲:setvbuf(stdout, NULL, _IONBF, 0);

有关管道与终端缓冲的完整说明,请参阅此answer,包括确定stdout缓冲的libc示例。