Передача данных от ребенка к родителю в nodejs

у меня есть родительский процесс nodejs, который запускает другой дочерний процесс nodejs. Дочерний процесс выполняет некоторую логику, а затем возвращает выходные данные родительскому процессу. Выход большой, и я пытаюсь использовать трубы для связи, как это предлагается в документации для ребенка.метод send () (который отлично работает BTW).

Я хотел бы, чтобы кто-то подскажет, как правильно строить этот канал связи. Я хочу иметь возможность отправлять данные от родителя к ребенку, а также отправлять данные из ребенка к родителю. Я немного запустил его, но он неполный (отправляет сообщение только от родителя к ребенку) и выдает ошибку.

Код Родительского Файла:

var child_process = require('child_process');

var opts = {
    stdio: [process.stdin, process.stdout, process.stderr, 'pipe']
};
var child = child_process.spawn('node', ['./b.js'], opts);

require('streamifier').createReadStream('test 2').pipe(child.stdio[3]);

ребенок файл с кодом:

var fs =  require('fs');

// read from it
var readable = fs.createReadStream(null, {fd: 3});

var chunks = []; 

readable.on('data', function(chunk) {
    chunks.push(chunk);
});

readable.on('end', function() {
    console.log(chunks.join().toString());
})

приведенный выше код выводит ожидаемый результат ("тест 2") вместе со следующей ошибкой:

events.js:85
      throw er; // Unhandled 'error' event
            ^
Error: shutdown ENOTCONN
    at exports._errnoException (util.js:746:11)
    at Socket.onSocketFinish (net.js:232:26)
    at Socket.emit (events.js:129:20)
    at finishMaybe (_stream_writable.js:484:14)
    at afterWrite (_stream_writable.js:362:3)
    at _stream_writable.js:349:9
    at process._tickCallback (node.js:355:11)
    at Function.Module.runMain (module.js:503:11)
    at startup (node.js:129:16)
    at node.js:814:3

Ответ:

родители:
var child_process = require('child_process');

var opts = {
    stdio: [process.stdin, process.stdout, process.stderr, 'pipe', 'pipe']
};
var child = child_process.spawn('node', ['./b.js'], opts);

child.stdio[3].write('First message.n', 'utf8', function() {
    child.stdio[3].write('Second message.n', 'utf8', function() {

    });
}); 

child.stdio[4].pipe(process.stdout);
ребенок:
var fs =  require('fs');

// read from it
var readable = fs.createReadStream(null, {fd: 3});

readable.pipe(process.stdout);
fs.createWriteStream(null, {fd: 4}).write('Sending a message back.');

3 ответов


ваш код работает, но с помощью пакета streamifier для создания потока чтения из строки ваш канал связи автоматически закрывается после передачи этой строки, что является причиной получения ошибки ENOTCONN.

чтобы иметь возможность отправлять несколько сообщений по потоку, рассмотрите возможность использования .write на нем. Вы можете называть это так часто, как вам нравится:

child.stdio[3].write('First message.\n');
child.stdio[3].write('Second message.\n');

если вы хотите использовать этот метод для отправки нескольких дискретных сообщений (что, я считаю, так и есть основываясь на вашем замечании об использовании child.send() before), это хорошая идея, чтобы использовать некоторый символ разделителя, чтобы иметь возможность разделить сообщения, когда поток читается в дочернем. В приведенном выше примере я использовал строки для этого. Полезный пакет для расщепления событие-трансляция.

теперь, чтобы создать другой канал связи от ребенка в родителе, просто добавьте еще одну "трубу" в свой stdio.

вы можете написать его в ребенок:

fs.createWriteStream(null, {fd: 4}).write('Sending a message back.');

и читайте Из него в родителе:

child.stdio[4].pipe(process.stdout);

это будет печатать " отправка сообщения обратно. к консоли.


я столкнулся с той же проблемой и использовал опцию {end:false} для исправления ошибки. К сожалению, принятый ответ работает только при обработке дискретных записей коротких объемов данных. Если у вас много данных (а не только коротких сообщений), вам нужно обработать управление потоком и использовать .write () не самый лучший. Для таких сценариев (большие передачи данных), его лучше использовать .функция pipe (), как первоначально в коде, для управления потоком.

В ошибка возникает из-за того, что читаемый поток в Родительском процессе пытается завершить и закрыть канал ввода записываемого потока дочернего процесса. Вы должны использовать {end: false} опция в Родительском канале процесса:

Исходный Код: require('streamifier').createReadStream('test 2').pipe(child.stdio[3]);

Предлагаемое Изменение: require('streamifier').createReadStream('test 2').pipe(child.stdio[3], {end:false});

см. подробности здесь из документации NodeJs: https://nodejs.org/dist/latest-v5.x/docs/api/stream.html#stream_readable_pipe_destination_options

надеюсь, это поможет кому-то еще столкнуться с этой проблемой.


вы можете сделать это с помощью fork()

Я только что решил этот вопрос для себя...fork() является версией более высокого уровня spawn, и рекомендуется использовать fork() вместо spawn() в целом.

если вы используете {silent:true} опция, stdio будет передаваться в родительский процесс

          const cp = require('child_process');

          const n = cp.fork(<path>, args, {
              cwd: path.resolve(__dirname),
              detached: true,
           });

          n.stdout.setEncoding('utf8');

          // here we can listen to the stream of data coming from the child process:
          n.stdout.on('data', (data) => {
            ee.emit('data',data);
          });

          //you can also listen to other events emitted by the child process
          n.on('error', function (err) {
            console.error(err.stack);
            ee.emit('error', err);
          });

          n.on('message', function (msg) {
            ee.emit('message', msg);
          });

          n.on('uncaughtException', function (err) {
            console.error(err.stack);
            ee.emit('error', err);
          });


          n.once('exit', function (err) {
             console.error(err.stack);
             ee.emit('exit', err);
          });