A colleague and I need to interface his C program and my Node.js script. I'm attempting to prove the concept of using stdio to pass messages between the two and so far, the concept isn't proven! The node script starts the executable as a child process on initialisation but then fails to send or receive data.
I have written a very simple C program that echos to stdout whatever it receives on stdin. I'm not a C programmer so hopefully I haven't done anything too shocking in 16 lines :p :
stream_echo.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFER_SIZE 255
int main(void) {
char * buffer = calloc(BUFFER_SIZE, 1);
while(fgets(buffer, BUFFER_SIZE, stdin) != NULL) {
//Echo back on stdout:
fprintf(stdout, "echo: %s", buffer);
}
}
And testing in the console shows it working as expected:
The node.js script that calls this executable is as follows:
child_stdio.js
(function() {
"use strict";
var jcp = require("child_process").spawn("./stream_echo", [], {
detached: false,
stdio: "pipe"
}),
counter = 0,
timer,
sendData = function() {
console.log("In sendData. Connected: " + jcp.connected);
counter += 1;
jcp.stdin.write("This is data " + counter + "\r\n");
timer = setTimeout(sendData, 2000);
};
//******** STDIN ********
jcp.stdin.on("close", (data) => {
console.log("stdin closed.");
if (timer) {
clearTimeout(timer);
}
});
//******** STDOUT ********
jcp.stdout.on("data", (data) => {
console.log("stdout: " + data);
});
jcp.stdout.on("close", (data) => {
console.log("stdout closed.");
});
//******** STDERR ********
jcp.stderr.on("data", (data) => {
console.log("stderr: " + data);
});
jcp.stderr.on("close", (data) => {
console.log("stderr closed.");
});
//******** PROCESS ********
jcp.on("close", (code, signal) => {
console.log("Child process closed.\nCode: " + code + "\nSignal: " + signal);
});
jcp.on("exit", (code, signal) => {
console.log("Child process exited.\nCode: " + code + "\nSignal: " + signal);
});
jcp.on("disconnect", () => {
console.log("Child process disconnected.");
});
console.log("jcp.pid: " + jcp.pid);
console.log("Connected: " + jcp.connected);
console.log("Calling sendData for the first time....");
sendData();
}());
When I run this script, multiple attempts to send data to the child process are made and no errors are reported (despite the connected
property of the process being false) but no messages are received back either. When I kill the child process, the stream close events and process close events are triggered and the script gracefully terminates.
I don't understand why connected
is false but the close events trigger. I feel this is a major clue.
Can anyone tell me what many hours trawling the Internet cannot?
When stdout
is not connected to a terminal it is block-buffered. That means the output is not going to be flushed until the buffer fills up or the application terminates.
Add fflush(stdout)
after fprintf
in you C application.