Node.JS : запись в дочерний процесс spawn после получения стандартных данных

#javascript #node.js #io #child-process

#javascript #node.js #io #дочерний процесс

Вопрос:

Что я пытаюсь сделать: я написал шахматный движок на c , который я скомпилировал в исполняемый файл. Сейчас я использую Node.JS, позволяющий этому движку взаимодействовать с API шахматного веб-сайта (чтобы пользователи и другие движки могли его оспаривать).

Я использую узел. child_process Модуль JS для создания a spawn , который облегчит обмен данными ввода-вывода между API и движком.

Чтобы сообщить движку, что началась новая игра, я пишу "UCIn" в процесс. Затем я жду вывода движка "id name {engine name}rnid author {my name}rnuciokrn" . После того, как я получу этот вывод из своего движка, мне нужно "isreadyn" будет выполнить обратную запись, чтобы позже он мог начать генерировать ходы.

Моя проблема: проблема, с которой я сталкиваюсь, заключается в том, что после моей первоначальной "UCIn" записи в процесс я вызываю child_process.spawn().stdin.end() . Кажется, что этот end() вызов должен где-то существовать, иначе я, мой процесс, не улавливает ввод, который я ему пишу.

Всякий раз, когда я пытаюсь выполнить запись "isreadyn" в дочерний процесс после получения выходных данных движка, я сталкиваюсь с этой ошибкой:

Ошибка [ERR_STREAM_WRITE_AFTER_END]: запись после завершения

Все это выглядит примерно так:

 const engineExePath = 'C:\Users\chopi\Desktop\chess-engine\maestro\uci.exe';
const childProcess = require('child_process');
const spawn_options = {
    cwd: null, env: null, detached: false
}

const engineStream = childProcess.spawn(engineExePath, [], spawn_options);
engineStream.stdout.on('data', function (data) {

    var result = data.toString();

    if (result == 'id name Maestrornid author dvdutchrnuciokrn') {
        //Here, we are listening to the response from the engine, and are now ready to spit back a message to it.
        //This is where the error is occurring
        engineStream.stdin.write('isreadyn');
    } else {
        console.log('no match');
    }

});

engineStream.stdin.write('ucin');
engineStream.stdin.end();
  

Что я пробовал: я пытался вызвать engineStream.stdin.end() , когда дочерний процесс закрывает свой поток через:

 engineStream.on('close', (code) => {
  engineStream.stdin.end();
});
  

Однако, когда я это делаю, кажется, что между моим файлом узла и моим дочерним процессом нет никакой связи, вроде как, когда engineStream.stdin.end() просто не вызывается вообще. Вся интеграция с этим методом будет выглядеть примерно так:

 const engineExePath = 'C:\Users\chopi\Desktop\chess-engine\maestro\uci.exe';
const childProcess = require('child_process');
const spawn_options = {
    cwd: null, env: null, detached: false
}

const engineStream = childProcess.spawn(engineExePath, [], spawn_options);
engineStream.stdout.on('data', function (data) {

    var result = data.toString();

    if (result == 'id name Maestrornid author dvdutchrnuciokrn') {
        //Here, we are listening to the response from the engine, and are now ready to spit back a message to it.
        engineStream.stdin.write('isreadyn');
    } else {
        console.log('no match');
    }

});

engineStream.on('close', (code) => {
  engineStream.stdin.end();
});

engineStream.stdin.write('ucin');
  

Что мне интересно:
Каков правильный способ облегчить этот обмен сообщениями между моим дочерним процессом и моим файлом узла?

Комментарии:

1. Работает ли это при отправке echo uci cmd вместо вашего процесса? Также data не гарантируется наличие строк. ввод буферизуется в виде блоков.

2. Запуск uci.exe , а затем ввод echo uci из cmd ничего не возвращает. Тем не менее, я установил исполняемый файл движка в графический интерфейс шахматного движка (который передает ходы, сделанные пользователем через графический интерфейс, движку и перемещается из движка обратно к пользователю), и там он работает нормально.

3. Извините, я имел в виду создание узла cmd вместо uci.exe . т.е. проверка, выполняет ли другой процесс Windows так, как вы хотите uci.exe , или это общая проблема платформы, записывающая в стандартный набор данных из узла.

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

5. Вы правы, cmd.exe создание и повторение некоторых данных, прослушивание эха и повторная запись позволяют мне писать несколько раз. Конечно, это требует от меня удаления engineStream.stdin.end() . Поскольку cmd.exe он может сделать это просто отлично, я рассмотрю причины, по которым пропуск этой строки uci.exe предотвратит вывод любых выходных данных в мой файл узла.