Node.js 与 C++ 的集成
Integration between Node.js and C++
我有一个 Node.js 应用程序,我希望能够将 JSON 对象发送到 C++ 应用程序中。
C++ 应用程序将使用 Poco 库 (pocoproject.org)。
我希望交互快速进行,因此最好不要使用文件或网络套接字。
我一直在研究这些领域:
- 管道
- 共享内存
- unixSockets
我应该关注什么,谁能指出我的方向到文档。和样本?
首先,需要多一些数据,给个好的建议。
一般来说,共享内存是最快的,因为不需要传输,但它也是最难保持良好状态的。不过,我不确定您能否使用 Node 做到这一点。
如果此程序仅 运行 用于此任务并关闭它可能值得将您的 JSON 作为启动参数发送到 CPP 程序
myCPPProgram.exe "JsonDataHere"
具有良好性能的最简单的事情应该是使用具有一些低开销数据帧格式的 Unix 域套接字的套接字连接。例如,两个字节的长度后跟 UTF-8 编码 JSON。在 C++ 方面,使用 Poco::Net::TCPServer
框架应该很容易实现。根据您的应用程序将来的发展方向,您可能 运行 会受到这种格式的限制,但如果它基本上只是流式传输 JSON 对象,那应该没问题。
为了使其更简单,您可以使用 WebSocket,它会为您处理框架,但会产生初始连接设置(HTTP 升级请求)的开销。甚至可以通过 Unix 域套接字 运行 WebSocket 协议。
然而,考虑到所有 JavaScript/node.js 开销,(仅限本地主机)TCP 套接字和 Unix 域套接字之间的性能差异甚至可能并不显着。此外,如果性能真的很重要,JSON 甚至可能不是正确的序列化格式。
无论如何,如果没有更详细的信息(JSON 数据的大小、消息频率),很难给出明确的建议。
我创建了一个 TCPServer,它似乎可以工作。但是,如果我关闭服务器并再次启动它,我会收到此错误:
Net Exception: Address already in use: /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] = '[=10=]';
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);
}
我所寻求的解决方案是使用 unix 域套接字。该解决方案将 运行 设置为 Raspbian 并且套接字文件位于 /dev/shm 中,它已安装到 RAM 中。
在 C++ 方面,我使用 Poco::Net::TCPServer 框架,如本文其他地方所述 post。
在Node.js这边,我使用了node-ipc模块(http://riaevangelist.github.io/node-ipc/)。
我有一个 Node.js 应用程序,我希望能够将 JSON 对象发送到 C++ 应用程序中。
C++ 应用程序将使用 Poco 库 (pocoproject.org)。
我希望交互快速进行,因此最好不要使用文件或网络套接字。 我一直在研究这些领域:
- 管道
- 共享内存
- unixSockets
我应该关注什么,谁能指出我的方向到文档。和样本?
首先,需要多一些数据,给个好的建议。
一般来说,共享内存是最快的,因为不需要传输,但它也是最难保持良好状态的。不过,我不确定您能否使用 Node 做到这一点。
如果此程序仅 运行 用于此任务并关闭它可能值得将您的 JSON 作为启动参数发送到 CPP 程序
myCPPProgram.exe "JsonDataHere"
具有良好性能的最简单的事情应该是使用具有一些低开销数据帧格式的 Unix 域套接字的套接字连接。例如,两个字节的长度后跟 UTF-8 编码 JSON。在 C++ 方面,使用 Poco::Net::TCPServer
框架应该很容易实现。根据您的应用程序将来的发展方向,您可能 运行 会受到这种格式的限制,但如果它基本上只是流式传输 JSON 对象,那应该没问题。
为了使其更简单,您可以使用 WebSocket,它会为您处理框架,但会产生初始连接设置(HTTP 升级请求)的开销。甚至可以通过 Unix 域套接字 运行 WebSocket 协议。
然而,考虑到所有 JavaScript/node.js 开销,(仅限本地主机)TCP 套接字和 Unix 域套接字之间的性能差异甚至可能并不显着。此外,如果性能真的很重要,JSON 甚至可能不是正确的序列化格式。
无论如何,如果没有更详细的信息(JSON 数据的大小、消息频率),很难给出明确的建议。
我创建了一个 TCPServer,它似乎可以工作。但是,如果我关闭服务器并再次启动它,我会收到此错误:
Net Exception: Address already in use: /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] = '[=10=]';
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);
}
我所寻求的解决方案是使用 unix 域套接字。该解决方案将 运行 设置为 Raspbian 并且套接字文件位于 /dev/shm 中,它已安装到 RAM 中。
在 C++ 方面,我使用 Poco::Net::TCPServer 框架,如本文其他地方所述 post。
在Node.js这边,我使用了node-ipc模块(http://riaevangelist.github.io/node-ipc/)。