1
votes

Intégration entre Node.js et C ++

J'ai une application Node.js que je souhaite pouvoir envoyer un objet JSON dans une application C ++.

L'application C ++ utilisera les bibliothèques Poco (pocoproject.org).

Je veux que l'interaction soit rapide, donc de préférence pas de fichiers ou de sockets réseau. J'ai étudié ces domaines:

  • Tuyaux
  • Mémoire partagée
  • unixSockets

Sur quoi dois-je me concentrer et quelqu'un peut-il me diriger vers des documents? et des échantillons?


4 commentaires

Je pense que vous allez devoir modifier cette question pour montrer ce que vous avez fait. Nous ne pouvons pas vraiment faire vos recherches à votre place. Je suggérerais de créer des exemples d'applications en utilisant ces 3 méthodes et de publier sur codereview.stackexchange.com pour voir si vous pouvez modifier quelque chose pour les améliorer.


La mémoire partagée peut être plus rapide, en particulier avec de grandes quantités de données, car il y a moins de copie des données. Cependant, vous devrez également faire une certaine forme de signalisation et de synchronisation, ce qui rend la tâche beaucoup plus difficile. Qu'est-ce que la rapidité de l'éclair? Vous devriez pouvoir atteindre plus de 10 000 requêtes par seconde sur une socket de domaine Unix pour les petits messages.


Êtes-vous sûr d'avoir besoin d'un IPC? Pour autant que je sache - node.js a une fonctionnalité d'addons natifs, qui peut être utilisée pour traiter du code natif (c, c ++, fortran, etc.)


Cela s'appelle nan btw.


4 Réponses :


0
votes

Tout d'abord, il faut plus de données pour donner de bons conseils.

En général, la mémoire partagée est la plus rapide, car aucun transfert n'est requis, mais c'est aussi la plus difficile à gérer. Je ne suis pas sûr que vous puissiez le faire avec Node.

Si ce programme ne s'exécute que pour cette tâche et se ferme, il peut valoir la peine d'envoyer simplement votre JSON au programme CPP en tant que paramètre de démarrage

myCPPProgram.exe "JsonDataHere"


1 commentaires

L'application Node.js récupère les données des capteurs. Je ne peux modifier la fonction que dans l'application Node.js qui détermine quoi faire lorsque les données du capteur sont arrivées. Je souhaite que ces données soient envoyées à une application C ++ qui fonctionne 24h / 24 et 7j / 7.



0
votes

La chose la plus simple avec des performances décentes devrait être une connexion socket utilisant des sockets de domaine Unix avec un format de trame de données à faible surcharge. Par exemple, une longueur de deux octets suivie d'un JSON encodé en UTF-8. Du côté C ++, cela devrait être facile à implémenter en utilisant le framework Poco :: Net :: TCPServer . En fonction de la destination de votre application dans le futur, vous pouvez rencontrer des limites de ce format, mais s'il s'agit essentiellement de diffuser des objets JSON, cela devrait aller.

Pour rendre cela encore plus simple, vous pouvez utiliser un WebSocket, qui se chargera du cadrage pour vous, au prix de la surcharge pour la configuration initiale de la connexion (demande de mise à jour HTTP). Peut même être possible d'exécuter le protocole WebSocket sur une socket de domaine Unix.

Cependant, la différence de performances entre une socket TCP (localhost uniquement) et une socket de domaine Unix peut même ne pas être significative, étant donné toute la surcharge de JavaScript / node.js. De plus, si les performances sont vraiment un problème, JSON peut même ne pas être le bon format de sérialisation pour commencer.

Quoi qu'il en soit, sans informations plus détaillées (taille des données JSON, fréquence des messages), il est difficile de donner une recommandation définitive.


3 commentaires

Les applications fonctionneront dans un premier temps sur Ubuntu et Raspbian. J'ai cherché dans les bibliothèques Poco la fonctionnalité IPC et j'ai trouvé: NamedEvent, Pipes et SharedMemory. Je suppose que NamedEvent n'est utilisé que pour signaler qu'un événement s'est produit, mais je ne sais pas comment interagir avec cela à partir de Node.js. Les tuyaux sont pris en charge dans Node.js, mais je ne suis pas sûr des performances. Je vois que Node.js a des fonctionnalités supplémentaires C ++ (NAN), mais je ne suis pas sûr que cela puisse interagir avec la fonctionnalité SharedMemory des bibliothèques Poco. Existe-t-il des Poco-samples avec des sockets Unix?


Je ne connais pas suffisamment Node.js pour savoir s'il existe des équivalents à NamedEvent et NamedMutex, en plus de la prise en charge de la mémoire partagée. Bien sûr, il serait possible d'écrire un module Node.js natif qui gère l'IPC en utilisant les classes Poco, mais l'effort n'en vaudrait probablement pas la peine. La configuration d'un Poco :: Net :: TCPServer devrait être simple, créez simplement un Poco :: Net :: SocketAddress en utilisant une chaîne de chemin absolu et transmettez-le au Poco :: Net :: ServerSocket sous-jacent. Notez que cela nécessite au moins la version 1.8.0 de Poco. Il n'y a probablement aucune différence de performances entre les canaux et les sockets de domaine Unix.


Quelle est la bonne façon de traiter l'erreur «Exception nette: adresse déjà utilisée: /tmp/app.SocketTest»?



0
votes

J'ai créé un TCPServer, qui semble fonctionner. Cependant, si je ferme le serveur et le redémarre, j'obtiens cette erreur:

Exception nette: adresse déjà utilisée: /tmp/app.SocketTest

Est-il impossible de se reconnecter au socket s'il existe?

Voici le code du 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);
}


2 commentaires

L'appel de socketFile.remove () après srv.stop (); résout le problème.


Voir aussi stackoverflow.com/questions/34873151/...



0
votes

La solution que j'ai choisie est d'utiliser des sockets de domaine unix. La solution fonctionnera sur une configuration Raspbian et le fichier socket est placé dans / dev / shm, qui est monté dans la RAM.

Du côté C ++, j'utilise le framework Poco :: Net :: TCPServer comme décrit ailleurs dans cet article.

Du côté Node.js, j'utilise le module node-ipc ( http: // riaevangelist .github.io / node-ipc / ).


0 commentaires