NodeJS child_process stdout,如果进程正在等待 stdin
NodeJS child_process stdout, if process is waiting for stdin
我正在开发一个应用程序,它允许编译和执行通过 api 给出的代码。
我要执行的二进制文件保存为 input_c
并且应该打印一个文本,询问用户的姓名并在收到输入后打印出另一个文本。
使用以下代码可以正常工作:第一个文本 - 输入(在终端上) - 第二个文本。
const {spawn} = require('child_process');
let cmd = spawn('input_c', [], {stdio: [process.stdin, process.stdout, process.stderr]});
输出:
$ node test.js
Hello, what is your name? Heinz
Hi Heinz, nice to meet you!
我喜欢单独处理 stdout、stderr 和 stdin,而不是将其写入终端。以下代码是我尝试实现与上述相同的行为:
const {spawn} = require('child_process');
let cmd = spawn('input_c');
cmd.stdout.on('data', data => {
console.log(data.toString());
});
cmd.stderr.on('data', data => {
console.log(data.toString());
});
cmd.on('error', data => {
console.log(data.toString());
});
// simulating user input
setTimeout(function() {
console.log('Heinz');
cmd.stdin.write('Heinz\n');
}, 3000);
输出:
$ node test.js
Heinz
Hello, what is your name? Hi Heinz, nice to meet you!
为了模拟用户输入,我在 3000 毫秒后写入标准输入。但是这里我没有直接在 运行 上接收到 stdout 中的第一个数据,它似乎在等待 stdin 并立即输出所有内容。
我怎样才能为我的第二个案例实现相同的行为?
以下 C 代码用于编译二进制文件,但任何等待用户输入的应用程序都可用于此目的:
#include <stdio.h>
int main() {
char name[32];
printf("Hello, what is your name? ");
scanf("%s", name);
printf("Hi %s, nice to meet you!", name);
return 0;
}
node-pty可以在这里使用来防止子进程的缓冲输出。
const pty = require('node-pty');
let cmd = pty.spawn('./input_c');
cmd.on('data', data => {
console.log(data.toString());
});
// simulating user input
setTimeout(function() {
console.log('Heinz');
cmd.write('Heinz\n');
}, 3000);
输出:
Hello, what is your name?
Heinz
Heinz
Hi Heinz, nice to meet you!
您遇到的 stdout.on()
事件在 spawn()
之后未被触发的问题出现是因为 node.js
生成子进程的方式。本质上,它创建 stream.pipe()
(默认情况下),它允许子进程在将输出发送到 stdout
之前缓冲输出,它是由节点提供的,这通常有利于性能。
但是,由于您需要实时输出并且您负责二进制文件,因此您可以简单地禁用内部缓冲。在 C
中,您可以通过将 setbuf(stdout, NULL);
添加到程序的开头来实现:
#include <stdio.h>
int main() {
setbuf(stdout, NULL);
char name[32];
printf("Hello, what is your name? ");
scanf("%31s", name);
printf("Hi %s, nice to meet you!", name);
return 0;
}
或者,您可以在每个 printf()
、puts()
等之后调用 fflush(stdout);
:
#include <stdio.h>
int main() {
char name[32];
printf("Hello, what is your name? "); fflush(stdout);
scanf("%31s", name);
printf("Hi %s, nice to meet you!", name); fflush(stdout);
return 0;
}
在子进程中禁用内部缓冲或触发显式刷新后,您将立即获得预期的行为,而无需任何外部依赖。
更新:
许多应用程序有意抑制或至少允许抑制 stdio 缓冲,因此您可能会找到相关的启动参数。例如,您可以使用 -u
选项启动 python
解释器二进制文件,这将 强制 stdin、stdout 和 stderr 完全无缓冲。还有几个与 nodejs
和 stdio buffering problems
相关的旧问题,您可能会发现有用,例如:
我正在开发一个应用程序,它允许编译和执行通过 api 给出的代码。
我要执行的二进制文件保存为 input_c
并且应该打印一个文本,询问用户的姓名并在收到输入后打印出另一个文本。
使用以下代码可以正常工作:第一个文本 - 输入(在终端上) - 第二个文本。
const {spawn} = require('child_process');
let cmd = spawn('input_c', [], {stdio: [process.stdin, process.stdout, process.stderr]});
输出:
$ node test.js
Hello, what is your name? Heinz
Hi Heinz, nice to meet you!
我喜欢单独处理 stdout、stderr 和 stdin,而不是将其写入终端。以下代码是我尝试实现与上述相同的行为:
const {spawn} = require('child_process');
let cmd = spawn('input_c');
cmd.stdout.on('data', data => {
console.log(data.toString());
});
cmd.stderr.on('data', data => {
console.log(data.toString());
});
cmd.on('error', data => {
console.log(data.toString());
});
// simulating user input
setTimeout(function() {
console.log('Heinz');
cmd.stdin.write('Heinz\n');
}, 3000);
输出:
$ node test.js
Heinz
Hello, what is your name? Hi Heinz, nice to meet you!
为了模拟用户输入,我在 3000 毫秒后写入标准输入。但是这里我没有直接在 运行 上接收到 stdout 中的第一个数据,它似乎在等待 stdin 并立即输出所有内容。
我怎样才能为我的第二个案例实现相同的行为?
以下 C 代码用于编译二进制文件,但任何等待用户输入的应用程序都可用于此目的:
#include <stdio.h>
int main() {
char name[32];
printf("Hello, what is your name? ");
scanf("%s", name);
printf("Hi %s, nice to meet you!", name);
return 0;
}
node-pty可以在这里使用来防止子进程的缓冲输出。
const pty = require('node-pty');
let cmd = pty.spawn('./input_c');
cmd.on('data', data => {
console.log(data.toString());
});
// simulating user input
setTimeout(function() {
console.log('Heinz');
cmd.write('Heinz\n');
}, 3000);
输出:
Hello, what is your name?
Heinz
Heinz
Hi Heinz, nice to meet you!
您遇到的 stdout.on()
事件在 spawn()
之后未被触发的问题出现是因为 node.js
生成子进程的方式。本质上,它创建 stream.pipe()
(默认情况下),它允许子进程在将输出发送到 stdout
之前缓冲输出,它是由节点提供的,这通常有利于性能。
但是,由于您需要实时输出并且您负责二进制文件,因此您可以简单地禁用内部缓冲。在 C
中,您可以通过将 setbuf(stdout, NULL);
添加到程序的开头来实现:
#include <stdio.h>
int main() {
setbuf(stdout, NULL);
char name[32];
printf("Hello, what is your name? ");
scanf("%31s", name);
printf("Hi %s, nice to meet you!", name);
return 0;
}
或者,您可以在每个 printf()
、puts()
等之后调用 fflush(stdout);
:
#include <stdio.h>
int main() {
char name[32];
printf("Hello, what is your name? "); fflush(stdout);
scanf("%31s", name);
printf("Hi %s, nice to meet you!", name); fflush(stdout);
return 0;
}
在子进程中禁用内部缓冲或触发显式刷新后,您将立即获得预期的行为,而无需任何外部依赖。
更新:
许多应用程序有意抑制或至少允许抑制 stdio 缓冲,因此您可能会找到相关的启动参数。例如,您可以使用 -u
选项启动 python
解释器二进制文件,这将 强制 stdin、stdout 和 stderr 完全无缓冲。还有几个与 nodejs
和 stdio buffering problems
相关的旧问题,您可能会发现有用,例如: