You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Node.js与C语言子进程的实时通信?

Node.js与C语言子进程实时通信问题解决

问题背景

在Debian GNU/Linux服务器上构建JavaScript API,需调用C语言编写的子进程实现实时通信,但当前Node.js仅能在子进程关闭后读取其stdout输出,无法在子进程写入stdout/stderr时立即响应。

当前代码

testNodeJS.js

const { spawn } = require("child_process");
var child = spawn("./testC.x");

child.stderr.on('data', function (data) {
    console.log(`child stderr:\n${data}`);
})

child.stdout.on('data', (data) => {
    console.log(`child stdout:\n${data}`);
});

child.stdin.write( 'FOO\n');
child.stdin.write( 'bar\n');

testC.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main( int argc, char * argv[] )
{
    char input_string[ 1023 + 1 ];

    printf("Start: %s\n", argv[0]);

    while ( 1 )
    {
        scanf("%s", &input_string);                     //reading stdin

        while(!getchar());                              //cleaning stdin

        printf( "Read: >%s<\n", input_string);  //write stdout

        if( strcmp( input_string, "end" ) == 0 )        //End testC.x
        {  
            printf("End: %s", argv[0] );
            return 0;
        }
    }
}

现象

  • 执行testNodeJS.js时,控制台无任何输出,仅保持等待状态,无法实时获取子进程输出
  • 若在JS代码中添加child.stdin.write( 'end\n');,子进程关闭后会一次性输出所有内容

问题原因

C语言标准库的printf输出缓冲策略会根据输出目标变化:

  • 当输出到终端时,采用行缓冲,换行时自动刷新缓冲区
  • 当输出被Node.js的spawn接管(非终端环境),会切换为全缓冲,只有缓冲区填满或进程退出时才会刷新输出,导致Node.js无法实时接收数据

解决方案

方案1:在C代码中手动刷新缓冲区

每次调用printf后,手动调用fflush(stdout)强制刷新输出缓冲区,同时修正原代码中scanf的参数错误(input_string本身是指针,无需加&):

修改后的testC.c:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main( int argc, char * argv[] )
{
    char input_string[ 1023 + 1 ];

    printf("Start: %s\n", argv[0]);
    fflush(stdout); // 强制刷新缓冲区

    while ( 1 )
    {
        scanf("%s", input_string); // 修正:去掉多余的&

        while(!getchar());

        printf( "Read: >%s<\n", input_string);
        fflush(stdout); // 每次输出后刷新

        if( strcmp( input_string, "end" ) == 0 )
        {  
            printf("End: %s\n", argv[0] ); // 补充换行符,确保输出完整
            fflush(stdout);
            return 0;
        }
    }
}

方案2:启动子进程时禁用缓冲

通过stdbuf命令启动C子进程,强制关闭stdout的缓冲:

修改testNodeJS.js中的spawn调用:

var child = spawn('stdbuf', ['-o', '0', './testC.x']);

-o 0表示将stdout的缓冲设置为0(无缓冲),这样C子进程的输出会直接发送给Node.js,无需修改C代码。

验证

修改后执行testNodeJS.js,控制台会实时输出:

child stdout:
Start: ./testC.x

child stdout:
Read: >FOO<

child stdout:
Read: >bar<

子进程保持运行状态,等待后续输入。

内容的提问来源于stack exchange,提问作者Banone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 01:12:06