说明
jcon-cpp
是一个用于 C++ 的 JSON-RPC 库,它允许开发者通过 JSON-RPC 协议进行进程间通信(IPC)。JSON-RPC 是一种轻量级的远程过程调用协议,基于 JSON 格式数据进行通信。基于MIT协议,最新代码基于Qt6实现。可通过Tcp和WebSocket实现RPC。
调整源码以适配Qt5
- 修改
json_rpc_server.cpp
的doCall
函数实现,将QMetaType return_type = QMetaType::fromName(return_type_name)
改为int return_type = QMetaType::type(return_type_name)
- 修改
json_rpc_websocket.cpp
的setupSocket
函数实现,将void (QWebSocket::*errorPtr)(QAbstractSocket::SocketError) = &QWebSocket::errorOccurred;
修改为void (QWebSocket::*errorPtr)(QAbstractSocket::SocketError) = &QWebSocket::error;
创建基于TCP的RPC服务器
示例代码
jcon::JsonRpcServer* startServer(QObject* parent, SocketType socket_type = SocketType::tcp, bool allow_notifications = false)
{
jcon::JsonRpcServer* rpc_server;
if (socket_type == SocketType::tcp) {
qDebug() << "Starting TCP server";
rpc_server = new jcon::JsonRpcTcpServer(parent);
} else {
qDebug() << "Starting WebSocket server";
rpc_server = new jcon::JsonRpcWebSocketServer(parent);
}
if (allow_notifications)
rpc_server->enableSendNotification(true);
auto service1 = new ExampleService;
auto service2 = new NotificationService;
rpc_server->registerServices({ service1, service2 });
rpc_server->listen(6002);
return rpc_server;
}
auto server = startServer(nullptr, SocketType::tcp);
//do something
delete server;
说明
-
rpc_server->enableSendNotification(true)
,用于设置RPC服务器是否可以主动推送消息给客户端 -
ExampleService、NotificationService
都是QObject
子类,通过元对象系统来定义、存储、调用相关接口,所以接口前需要定义成Q_INVOKABLE
#pragma once #include <QObject> class ExampleService : public QObject { Q_OBJECT public: ExampleService(); virtual ~ExampleService(); Q_INVOKABLE int getRandomInt(int limit); Q_INVOKABLE QString printMessage(const QString& msg); Q_INVOKABLE void printNotification(const QString& msg); Q_INVOKABLE void namedParams(QString& msg, int answer); };
-
rpc_server->registerServices
,将接口服务类注册到RPC服务器中,有两种方式:注册普通服务、注册命名空间服务。//注册普通服务 //m_services结构为QMap<QObject*, QString>,此时key存储的是QObject接口类,value为空 void JsonRpcServer::registerServices(const QObjectList& services) { m_services.clear(); for (auto s : services) { m_services[s] = ""; } m_ns_separator = ""; } //调用 auto service1 = new ExampleService; auto service2 = new NotificationService; rpc_server->registerServices({ service1, service2 });
//注册命名空间服务 //m_services结构为QMap<QObject*, QString>,此时key存储的是QObject接口类,value为对应服务的命名空间字符串 //ns_separator是一个用于分隔命名空间和方法名的字符串,默认为 / void JsonRpcServer::registerServices(const ServiceMap& services, const QString& ns_separator) { m_services = services; m_ns_separator = ns_separator; } //调用 auto service1 = new ExampleService; auto service2 = new OtherService; auto service3 = new NotificationService; rpc_server->registerServices( { { service1, "ex/myFirstNamespace" }, { service2, "ex/myOtherNamespace" }, { service3, "ex/myNotificationNamespace" } }, "/");
-
rpc_server->listen(6002)
监听某端口,JsonRpcServer
有两个子类:JsonRpcTcpServer、JsonRpcWebSocketServer
,JsonRpcTcpServer
实际就是实现了一个QTcpServer
监听端口、客户端连接时创建Socket
对象、Socket
有请求时通过元对象系统找到对应的函数执行并返回结果/*class JsonRpcTcpServer*/ //1.JsonRpcTcpServer构造函数,处理客户端连接 m_server.connect(&m_server, &QTcpServer::newConnection, this, &JsonRpcTcpServer::newConnection); //2.JsonRpcTcpServer::newConnection,创建相关通信对象 QTcpSocket* tcp_socket = m_server.nextPendingConnection(); auto rpc_socket = std::make_shared<JsonRpcTcpSocket>(tcp_socket); auto endpoint = std::shared_ptr<JsonRpcEndpoint>(new JsonRpcEndpoint(rpc_socket, log(), this), [this](JsonRpcEndpoint* obj) { if (this->m_server.isListening()) { obj->deleteLater(); } else { delete obj; } }); connect(endpoint.get(), &JsonRpcEndpoint::jsonObjectReceived, this, &JsonRpcServer::jsonRequestReceived); //3.JsonRpcServer::jsonRequestReceived,处理客户端请求 //request是请求数据,json格式;socket是对应的通信对象 void JsonRpcServer::jsonRequestReceived(const QJsonObject& request, QObject* socket) { //校验json的key:jsonrpc if (request.value("jsonrpc").toString() != "2.0") { logError("invalid protocol tag"); return; } //获取json的key:method QString method_name = request.value("method").toString(); //获取json的key:params QVariant params = request.value("params").toVariant(); //获取json的key:id QString request_id = request.value("id").toVariant().toString(); //从存储的元对象中找到对应的函数并执行 dispatch(method_name, params, return_value) }
创建基于TCP的RPC客户端
示例代码
jcon::JsonRpcClient* startClient(QObject* parent, SocketType socket_type = SocketType::tcp, bool allow_notifications = false) { jcon::JsonRpcClient* rpc_client; if (socket_type == SocketType::tcp) { rpc_client = new jcon::JsonRpcTcpClient(parent); rpc_client->connectToServer("127.0.0.1", 6002); } else { rpc_client = new jcon::JsonRpcWebSocketClient(parent); // This is just to illustrate the fact that connectToServer also accepts // a QUrl argument. rpc_client->connectToServer(QUrl("ws://127.0.0.1:6002")); } if (allow_notifications) rpc_client->enableReceiveNotification(true); return rpc_client; } auto rpc_client = startClient(&app, SocketType::tcp);
说明
- 调用通知类接口,无返回,通过函数名调用
rpc_client->notification("printNotification", "hello, notification");
- 异步调用接口,有返回,通过函数名调用
auto req = rpc_client->callAsync("getRandomInt", 10); req->connect(req.get(), &jcon::JsonRpcRequest::result, [](const QVariant& result) { qDebug() << "result of asynchronous RPC call:" << result; }); req->connect(req.get(), &jcon::JsonRpcRequest::error, [](int code, const QString& message) { qDebug() << "RPC error:" << message << " (" << code << ")"; });
- 同步调用接口,有返回,通过函数名调用
auto result = rpc_client->call("getRandomInt", 100); if (result->isSuccess()) { qDebug() << "result of synchronous RPC call:" << result->result(); } else { qDebug() << "RPC error:" << result->toString(); } //call里通过事件循环等待完成
- 异步调用接口,参数命名化方式,有返回,通过函数名调用
//将参数存入QVariantMap,参数1是msg,参数2是answer auto req = rpc_client->callAsyncNamedParams("namedParams", QVariantMap{ {"msg", "hello, world"}, {"answer", 42} }); req->connect(req.get(), &jcon::JsonRpcRequest::result, [](const QVariant& result) { qDebug() << "result of asynchronous RPC call:" << result; }); req->connect(req.get(), &jcon::JsonRpcRequest::error, [](int code, const QString& message) { qDebug() << "RPC error:" << message << " (" << code << ")"; });