Интеграция между Node.js и C ++ - PullRequest
0 голосов
/ 24 января 2019

У меня есть приложение Node.js, которое я хочу иметь возможность отправлять JSON-объект в приложение C ++.

Приложение C ++ будет использовать Poco-библиотеки (pocoproject.org).

Я хочу, чтобы взаимодействие было быстрым, поэтому желательно, чтобы не было файлов или сетевых сокетов. Я искал в этих областях:

  • Трубы
  • Общая память
  • unixSockets

На чем я должен сосредоточиться, и кто-то может указать мое направление на документы. а образцы?

Ответы [ 4 ]

0 голосов
/ 31 января 2019

Решение, которое я выбрал, заключается в использовании доменных сокетов unix.Решение будет работать на Raspbian-setup, а файл сокета помещается в / dev / shm, который монтируется в RAM.

На стороне C ++ я использую инфраструктуру Poco :: Net :: TCPServerкак описано в этом посте.

На стороне Node.js я использую модуль node-ipc (http://riaevangelist.github.io/node-ipc/).

0 голосов
/ 25 января 2019

Самой простой вещью с достойной производительностью должно быть сокетное соединение с использованием доменных сокетов Unix с некоторым форматом фрейма данных с минимальными издержками.Например, двухбайтовая длина, за которой следует кодированный в кодировке UTF-8 JSON.На стороне C ++ это должно быть легко реализовано с использованием фреймворка Poco::Net::TCPServer.В зависимости от того, куда пойдет ваше приложение в будущем, вы можете столкнуться с ограничениями этого формата, но если это в основном просто потоковая передача объектов JSON, все будет хорошо.

Чтобы сделать его еще проще, вы можете использовать WebSocket, который позаботится о кадрировании, за счет накладных расходов на начальную настройку соединения (запрос на обновление HTTP).Может даже быть возможно запустить протокол WebSocket через сокет домена Unix.

Однако разница в производительности между TCP-сокетом (только для локального хоста) и доменным сокетом Unix может быть даже незначительной, учитывая все накладные расходы JavaScript / node.js.Кроме того, если производительность действительно является проблемой, JSON может даже не быть правильным форматом сериализации для начала.

В любом случае, без более подробной информации (размер данных JSON, частота сообщений) трудно дать конкретную рекомендацию.

0 голосов
/ 29 января 2019

Я создал TCPServer, который, кажется, работает. Однако, если я закрываю сервер и запускаю его снова, я получаю эту ошибку:

Net Exception: Адрес уже используется: /tmp/app.SocketTest

Разве невозможно повторно подключить к розетке, если она существует?

Вот код для TCPServer:

#include "Poco/Util/ServerApplication.h"
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/File.h"
#include <fstream>
#include <iostream>

using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::Net::TCPServer;
using Poco::Net::TCPServerConnection;
using Poco::Net::TCPServerConnectionFactory;
using Poco::Net::SocketAddress;
using Poco::Util::ServerApplication;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;



class UnixSocketServerConnection: public TCPServerConnection
    /// This class handles all client connections.
{
public:
    UnixSocketServerConnection(const StreamSocket& s): 
        TCPServerConnection(s)
    {
    }

    void run()
    {
        try
        {
            /*char buffer[1024];
            int n = 1;
            while (n > 0)
            {
                n = socket().receiveBytes(buffer, sizeof(buffer));
                EchoBack(buffer);
            }*/

            std::string message;
            char buffer[1024];
            int n = 1;
            while (n > 0)
            {
                n = socket().receiveBytes(buffer, sizeof(buffer));
                buffer[n] = '\0';
                message += buffer;
                if(sizeof(buffer) > n && message != "")
                {
                    EchoBack(message);
                    message = "";
                }
            }
        }
        catch (Poco::Exception& exc)
        {
            std::cerr << "Error: " << exc.displayText() << std::endl;
        }
        std::cout << "Disconnected." << std::endl;
    }

private:
    inline void EchoBack(std::string message)
    {
        std::cout << "Message: " << message << std::endl;
        socket().sendBytes(message.data(), message.length());
    }
};

class UnixSocketServerConnectionFactory: public TCPServerConnectionFactory
    /// A factory
{
public:
    UnixSocketServerConnectionFactory()
    {
    }

    TCPServerConnection* createConnection(const StreamSocket& socket)
    {
        std::cout << "Got new connection." << std::endl;
        return new UnixSocketServerConnection(socket);
    }

private:

};

class UnixSocketServer: public Poco::Util::ServerApplication
    /// The main application class.
{
public:
    UnixSocketServer(): _helpRequested(false)
    {
    }

    ~UnixSocketServer()
    {
    }

protected:
    void initialize(Application& self)
    {
        loadConfiguration(); // load default configuration files, if present
        ServerApplication::initialize(self);
    }

    void uninitialize()
    {
        ServerApplication::uninitialize();
    }

    void defineOptions(OptionSet& options)
    {
        ServerApplication::defineOptions(options);

        options.addOption(
            Option("help", "h", "display help information on command line arguments")
                .required(false)
                .repeatable(false));
    }

    void handleOption(const std::string& name, const std::string& value)
    {
        ServerApplication::handleOption(name, value);

        if (name == "help")
            _helpRequested = true;
    }

    void displayHelp()
    {
        HelpFormatter helpFormatter(options());
        helpFormatter.setCommand(commandName());
        helpFormatter.setUsage("OPTIONS");
        helpFormatter.setHeader("A server application to test unix domain sockets.");
        helpFormatter.format(std::cout);
    }

    int main(const std::vector<std::string>& args)
    {
        if (_helpRequested)
        {
            displayHelp();
        }
        else
        {
            // set-up unix domain socket
            Poco::File socketFile("/tmp/app.SocketTest");
            SocketAddress unixSocket(SocketAddress::UNIX_LOCAL, socketFile.path());

            // set-up a server socket
            ServerSocket svs(unixSocket);
            // set-up a TCPServer instance
            TCPServer srv(new UnixSocketServerConnectionFactory, svs);
            // start the TCPServer
            srv.start();
            // wait for CTRL-C or kill
            waitForTerminationRequest();
            // Stop the TCPServer
            srv.stop();
        }
        return Application::EXIT_OK;
    }

private:
    bool _helpRequested;
};

int main(int argc, char **argv) {
    UnixSocketServer app;
    return app.run(argc, argv);
}
0 голосов
/ 24 января 2019

Прежде всего, необходимы дополнительные данные, чтобы дать хороший совет.

В общем случае разделяемая память самая быстрая, так как передача не требуется, но ее также трудно поддерживать в порядке. Я не уверен, что вы сможете сделать это с помощью Node.

Если эта программа работает только для этой задачи и ее закрытие, возможно, стоит просто отправить JSON в программу CPP в качестве параметра запуска

myCPPProgram.exe "JsonDataHere"
...