IPC на терминальном сервере с C/C++ и nw.js/node.js/node-native-module (C++)?
У меня есть Win32-DLL (C++), которая загружается как плагин в другое приложение. DLL запускает экземпляр nw.js (ShellExecuteEx и SEE_MASK_NOCLOSEPROCESS) и завершает его при выгрузке DLL (посредством hInstance ShellExecuteEx). Мне нужен способ отправить строку (обычный ansi) в nw-процесс и получить ответ (также строку). По старинке был простой http-запрос с ответом в теле. Но среда изменяется во время разработки, "пакет" app-dll-nw запускается несколько раз одним и тем же пользователем, а несколько пользователей запускаются на одном компьютере (терминальном сервере). Таким образом, перечисление портов "невозможно" (да, случайные порты или синглтон nw, но нет).
Я нашел разные способы:
- сокет - проблема с перечислением портов
- wm_copydata/wm_... - нужен собственный плагин nw со скрытым окном (без нативного способа nw); нет системы запрос-ответ
- RPC - проблема с перечислением портов
- DDE - нет нативного способа javascript (найден модуль, который использует.net); В старые времена Delphi DDE была не такой простой задачей, и она несколько раз терпела неудачу без какой-либо логики.
- общая память - нет опыта; ожидания: асинхронный, триггер?
- общий файл - нет опыта; ожидания: асинхронный, триггер (наблюдатель за изменением файла), но проблемы с синхронизацией, возможен собственный способ js
- именованная труба - нет опыта; ожидания: win32-api и т.п. как система чата (in-pipe [отправить трансляцию] и out-pipe [принять трансляцию], или оба в одном)? Если да, я могу использовать одно имя для всех экземпляров, использовать уникальные идентификаторы и ждать правильного ответа.
Что такое хороший и простой способ общения, такой как http-way, но без сетевого взаимодействия?
Обновление 1: модуль узла "net" может создать сервер для именованного канала. Первый тест, послав строку из dll в nw, прошел успешно.
var server = net.createServer(function(stream) {
stream.on('data', function(c) {
console.log('data:', c.toString());
});
stream.on('end', function() {
//server.close();
});
});
server.listen('\\\\.\\pipe\\MyAppDynamicGUID');
Обновление 2 - Мое решение
С именованным каналом и упрощенной версией https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx я нашел работающий метод.
Сервер в nw.js:
var server = net.createServer(function(req) {
req.on('data', function(c) {
console.log(c.toString());
req.write('123|Hello World', 'ascii');
});
});
server.listen('\\\\.\\pipe\\MyAppDynamicGUID');
Клиент на C++ (без постоянного соединения, странная обработка строк, упрощенная обработка ошибок):
static std::string PipenameA = "\\\\.\\pipe\\MyAppDynamicGUID";
#define BUFSIZE 512
std::string SendPipeRequestA(std::string sRequest) {
DWORD dwToWrite, dwWritten, dwRead;
BOOL bSuccess;
char chBuf[BUFSIZE];
std::vector<char> buffer;
HANDLE hPipe = CreateFileA(PipenameA.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hPipe == INVALID_HANDLE_VALUE)
return "-1|Pipe-Error 1 (connect)";
dwToWrite = (lstrlenA(sRequest.c_str())+1)*sizeof(char);
bSuccess = WriteFile(hPipe, sRequest.c_str(), dwToWrite, &dwWritten, NULL);
if (!bSuccess)
return "-1|Pipe-Error 2 (write)";
do {
bSuccess = ReadFile(hPipe, chBuf, BUFSIZE*sizeof(char), &dwRead, NULL);
if (!bSuccess && GetLastError() != ERROR_MORE_DATA)
break;
buffer.insert(buffer.end(), chBuf, chBuf + dwRead);
} while (!bSuccess);
std::string sResponse(&buffer[0]);
CloseHandle(hPipe);
return sResponse.c_str();
}
// Джонни
2 ответа
Ответы, которые вы получите, будут основаны на мнении, знайте об этом.
Вы можете ввести данные в модуль JS в качестве аргумента командной строки, напримерstart nw.js MyData
и получить его в JS с process.argv
,
Теперь отправка данных обратно в исполняемые файлы / библиотеки C++ немного сложна. если вы выполняете shell-процесс, вы можете иметь дескриптор к нему. Вы можете распечатать данные в стандартный вывод из части JS и прочитать их в собственном приложении, получив дескриптор STDOUT из дескриптора процесса.
Зарегистрировать ваше приложение nw.js с пользовательским URL-адресом должно быть элегантным способом. Такие как "github://", "thunder://", "twitter://"
На окнах вы можете взглянуть на:
https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
С помощью пользовательского URL вы можете использовать простые аргументы для nw.js в режиме одного экземпляра. Увидеть:
https://github.com/nwjs/nw.js/wiki/Handling-files-and-arguments
Если требуется больше данных, может помочь base64 или даже больше методом сжатия LZ-String.