node.js 不会捕获异步 C++ .exe 文件的所有输出

Node.js Does Not Capture All Output from Asynchronous C++ .exe File

提问人:dotenv9 提问时间:11/6/2023 更新时间:11/6/2023 访问量:18

问:

Stack Overflow 社区!

我在将 Node.js 与异步 C++ 代码连接时遇到了问题。我有一个用 C++ 编写的可执行文件并编译成 .exe,它使用异步代码。具体而言,某些数据是从异步函数输出的,该函数在代码中的所有后续和类似命令之后执行。cout

问题在于,例如,当使用 或 从 Node.js 运行此 .exe 文件时,并非所有输出都被 Node.js 捕获。异步函数生成的数据似乎没有进入 Node.js 能够捕获的输出流。child_process.execchild_process.spawn

下面是一个简化的 C++ 代码示例,演示了此问题:

const { spawn } = require('child_process')
const os = require('os')
const path = require('path')
const fs = require('fs')

let fetch

import('node-fetch').then(module => {
    fetch = module.default
})

const Router = require('koa-router')
const router = new Router()
let apiScript = null

let accumulatedData = ""

let resolveScriptOutput

function waitForScriptResponse() {
    return new Promise((resolve) => {
        resolveScriptOutput = resolve
    })
}

const ensureScriptRunning = async () => {
    if (apiScript) return

    const platform = os.platform()

    try {
        if (platform === 'linux') {
            apiScript = spawn('bash', ['-c', './TestApp'], { stdio: ['pipe', 'pipe', 'pipe'] })
        } else if (platform === 'win32') {
            apiScript = spawn('ConsoleScrach', [], { stdio: ['pipe', 'pipe', 'pipe'] })
            // apiScript = spawn(path.join(process.resourcesPath, 'ConsoleScrach.exe'), [], { stdio: ['pipe', 'pipe', 'pipe'] })
        } else {
            console.error("Unsupported OS platform")
            return
        }

        apiScript.stderr.on('data', (data) => {
            console.error(`Ошибка скрипта: ${data}`)
        })

        apiScript.on('close', (code) => {
            console.log(`Процесс скрипта завершен с кодом ${code}`)
            apiScript = null; // Позволяет перезапустить процесс при следующем запросе
        })


        apiScript.stdout.on('data', (data) => {
            const outputData = data.toString().trim();
            console.log(`Получены данные от скрипта в: ${new Date().getHours()}:${new Date().getMinutes()}:${new Date().getSeconds()}`)
            console.log('Получены данные от скрипта:', outputData);

            accumulatedData += outputData;

            const jsonMatch = outputData.match(/{[\s\S]*}/);
            if (jsonMatch) {
                try {
                    const jsonObject = JSON.parse(jsonMatch[0])
                    if (resolveScriptOutput) {
                        resolveScriptOutput(jsonObject)
                        resolveScriptOutput = null
                    }

                    // Очистите accumulatedData после успешного разбора JSON
                    accumulatedData = ""
                } catch (parseError) {
                    console.error('Ошибка при попытке разобрать JSON:', parseError)
                    if (resolveScriptOutput) {
                        resolveScriptOutput({ error: 'Invalid JSON received' })
                        resolveScriptOutput = null
                    }
                }
            } else {
                console.warn('Не найдено строк JSON в выводе');
            }
        });

    } catch (error) {
        console.error('Ошибка при запуске или обработке скрипта:', error)
    }
}

router.post('/send-command', async (ctx) => {

    const requestBody = JSON.stringify(ctx.request.body)
    await ensureScriptRunning()
    console.log('Отправка команды:', requestBody)
    console.log(ctx.request.body)
    try {
        apiScript.stdin.write(requestBody + '\n', (err) => {
            console.log(`Команда отправлена в исполняемый файл в: ${new Date().getHours()}:${new Date().getMinutes()}:${new Date().getSeconds()}`)
            if (err) {
                console.error('Ошибка при записи в stdin:', err)
                ctx.status = 500
                ctx.body = { error: 'Ошибка при отправке команды' }
                return
            }
        })

        const scriptResponse = await waitForScriptResponse()

        ctx.body = scriptResponse
    } catch (error) {
        console.error('Произошла ошибка при обработке запроса:', error)
        ctx.status = 500
        ctx.body = { error: 'Внутренняя ошибка сервера' }
    }
})
case 4: {
    std::cout << "Starting case 4 start" << std::flush;
    unsigned char comadStartEnd[] = { 0x07};
    DWORD dwSize = sizeof(comadStartEnd);
    DWORD dwBytesWritten = 0;
    SendComTread(comadStartEnd, dwSize, dwBytesWritten);
    std::cout << "Starting case 4 SendComTread end" << std::flush;


This SendComTread
void SendComTread(unsigned char* data, DWORD dwSize, DWORD dwBytesWritten)
{
    BOOL iRet;

    std::string message;

    message += "SendComTread start";

    uint8_t* SendBuff = new uint8_t[(dwSize + 4) * 2]{};
    uint8_t* SendBuff2 = new uint8_t[(dwSize + 4) * 2]{ 0 };
    memcpy(SendBuff, data, dwSize);

    uint8_t crc = Crc8(SendBuff, dwSize);
    memcpy(SendBuff + dwSize, &crc, sizeof(uint8_t));

    int pos = cobsEncode(SendBuff, dwSize + 1, SendBuff2 + 1);

    iRet = WriteFile(hSerial, SendBuff2, pos + 2, &dwBytesWritten, NULL);

    message += std::to_string(iRet);
    message += "SendComTread end";

    std::cout << message << std::flush;
}

我希望看到程序的所有输出,包括 SendComTread 行,但是当我从 Node.js 运行它时,stdout 中缺少这一行。但是,如果我直接从命令行运行 .exe 文件,则所有输出都会正确显示。

如何确保 Node.js 正确捕获所有输出(包括异步输出)?

任何帮助将不胜感激。谢谢!

C++ 节点.js 异步 标准输出 子进程

评论


答: 暂无答案