开源库:jcon-cpp

ops/2025/1/12 9:10:20/

说明

jcon-cpp 是一个用于 C++ 的 JSON-RPC 库,它允许开发者通过 JSON-RPC 协议进行进程间通信(IPC)。JSON-RPC 是一种轻量级的远程过程调用协议,基于 JSON 格式数据进行通信。基于MIT协议,最新代码基于Qt6实现。可通过Tcp和WebSocket实现RPC。

调整源码以适配Qt5

  • 修改json_rpc_server.cppdoCall函数实现,将QMetaType return_type = QMetaType::fromName(return_type_name)改为int return_type = QMetaType::type(return_type_name)
  • 修改json_rpc_websocket.cppsetupSocket函数实现,将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_OBJECTpublic: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、JsonRpcWebSocketServerJsonRpcTcpServer实际就是实现了一个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:jsonrpcif (request.value("jsonrpc").toString() != "2.0") {logError("invalid protocol tag");return;}//获取json的key:methodQString method_name = request.value("method").toString();//获取json的key:paramsQVariant params = request.value("params").toVariant();//获取json的key:idQString 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 << ")";});
    

http://www.ppmy.cn/ops/149403.html

相关文章

一个基于Spring Boot的简单网吧管理系统

一个基于Spring Boot的简单网吧管理系统的案例代码。这个系统包括用户管理、电脑管理、上机记录管理等功能。代码结构清晰&#xff0c;适合初学者学习和参考。 1. 项目结构 src/main/java/com/example/netbarmanagement├── controller│ ├── ComputerController.jav…

[读书日志]从零开始学习Chisel 第十篇:Scala的模式匹配(敏捷硬件开发语言Chisel与数字系统设计)

7. Scala的模式匹配 7.1 样例类和对象 定义类时&#xff0c;如果在最前面加上关键字case&#xff0c;则这个类就被称为样例类。Scala的编译器自动对样例类添加一些语法便利&#xff1a; 添加一个与类同名的工厂方法&#xff0c;可以通过类名(参数)来构造对象&#xff0c;而不…

使用 Multer 上传图片到阿里云 OSS

文件上传到哪里更好&#xff1f; 上传到服务器本地 上传到服务器本地&#xff0c;这种方法在现今商业项目中&#xff0c;几乎已经见不到了。因为服务器带宽&#xff0c;磁盘 IO 都是非常有限的。将文件上传和读取放在自己服务器上&#xff0c;并不是明智的选择。 上传到云储存…

【ArcGIS Pro微课1000例】0065:制作千层饼多图层叠加效果

文章目录 一、新建场景工程并加载数据二、图层符号化1.dem图层2. TIN图层3. 等高线4. 影像三、设置高程偏移四、三维地形显示一、新建场景工程并加载数据 打开ArcGIS PRo,新建一个局部场景,命名为千层饼。 移除工程默认加载的图层。 点击【添加数据】。 添加配套实验数据包0…

《机器学习》从入门到实战——决策树

目录 一、简介 二、基本结构 三、构建过程 四、API接口解析 1、决策树--分类 &#xff08;1&#xff09;、接口调用方法 &#xff08;2&#xff09;、参数解析 2、决策树--回归 &#xff08;1&#xff09;、接口调用方法 &#xff08;2&#xff09;、参数解析 五、代…

任务调度系统Quartz.net详解2-Scheduler、Calendar及Listener

任务调度系统Quartz.net详解2-Scheduler、Calendar及Listener Scheduler 调度器scheduler是Quartz中的独立工作容器&#xff0c;所有的Trigger和Job都需要注册到scheduler中才能工作。我们可以通过SchedulerFactory来获取scheduler实例。如下&#xff1a; //1.获取默认的标准…

Chart.js 雷达图:数据可视化利器

Chart.js 雷达图:数据可视化利器 引言 在数据可视化的领域中,雷达图以其独特的展示方式,成为了一种非常受欢迎的数据展现工具。雷达图能够将多个量化变量的数据以二维图表的形式展示出来,使得观察者能够快速地理解和比较不同数据集之间的差异。Chart.js 是一个强大的 Jav…

Gitlab-Runner配置

原理 Gitlab-Runner是一个非常强大的CI/CD工具。它可以帮助我们自动化执行各种任务&#xff0c;如构建、测试和部署等。Gitlab-Runner和Gitlab通过API通信&#xff0c;接收作业并提交到执行队列&#xff0c;Gitlab-Runner从队列中获取作业&#xff0c;并允许在不同环境下进行作…