【jsonRpc项目】RCP服务测试

目录

一.服务端代码编写

二.同步请求客户端代码编写

三.异步请求客户端代码编写

四.回调请求客户端代码编写


事实上,现在我们借助

  • 服务器的RpcRouter
  • 模块客户端的Requestor模块和RpcCaller模块
  • 公共端的所有代码

就能实现基本的JSON-RPC服务了

一.服务端代码编写

server.cpp

cpp 复制代码
// 引入必要的头文件
#include "../../common/message.hpp"       // 消息相关的基类和定义
#include "../../common/net.hpp"           // 网络通信相关的类和工厂
#include "../../common/dispatcher.hpp"    // 消息分发器
#include "../../server/rpc_router.hpp"    // RPC路由器,用于处理RPC请求

// 定义一个简单的加法函数,作为RPC服务的实现
// @param req: 输入参数,包含两个整数 num1 和 num2
// @param rsp: 输出参数,用于返回计算结果
void Add(const Json::Value &req, Json::Value &rsp) {
    // 从请求中提取第一个参数 num1 并转换为整数
    int num1 = req["num1"].asInt();
    // 从请求中提取第二个参数 num2 并转换为整数
    int num2 = req["num2"].asInt();
    // 计算两个数的和并赋值给响应
    rsp = num1 + num2;
}

// main函数:程序入口点
int main()
{
    // 创建消息分发器实例,用于根据消息类型将消息分发到相应的处理器
    auto dispatcher = std::make_shared<jsonRpc::Dispatcher>();
    
    // 创建RPC路由器实例,用于管理和调用注册的RPC方法
    auto router = std::make_shared<jsonRpc::server::RpcRouter>();
    
    // 创建服务描述工厂对象,用于构建服务描述信息
    // 使用unique_ptr管理,确保工厂对象的资源得到正确释放
    std::unique_ptr<jsonRpc::server::SDescribeFactory> desc_factory(new jsonRpc::server::SDescribeFactory());
    
    // 配置服务描述信息:
    desc_factory->setMethodName("Add");  // 设置方法名称为"Add"
    
    // 设置第一个参数"num1"的描述,指定其类型为整数
    desc_factory->setParamsDesc("num1", jsonRpc::server::VType::INTEGRAL);
    
    // 设置第二个参数"num2"的描述,指定其类型为整数
    desc_factory->setParamsDesc("num2", jsonRpc::server::VType::INTEGRAL);
    
    // 设置返回值的类型为整数
    desc_factory->setReturnType(jsonRpc::server::VType::INTEGRAL);
    
    // 设置回调函数,即实际处理请求的Add函数
    desc_factory->setCallback(Add);
    
    // 通过工厂构建完整的服务描述对象,并将其注册到RPC路由器中
    router->registerMethod(desc_factory->build());
    
    // 创建一个回调函数,用于将RPC请求转发给路由器的处理函数
    // std::bind将RpcRouter::onRpcRequest方法与router对象绑定
    auto cb = std::bind(&jsonRpc::server::RpcRouter::onRpcRequest, router.get(), std::placeholders::_1, std::placeholders::_2);
    
    // 将回调函数注册到分发器中,当收到REQ_RPC类型的消息时,调用此回调
    dispatcher->registerHandler<jsonRpc::RpcRequest>(jsonRpc::MType::REQ_RPC, cb); 

    // 创建一个JSON-RPC服务器实例,监听端口9090
    // ServerFactory::create是一个静态工厂方法,用于创建服务器实例
    auto server = jsonRpc::ServerFactory::create(9090);
    
    // 创建消息处理回调函数,将服务器收到的所有消息转发给分发器处理
    auto message_cb = std::bind(&jsonRpc::Dispatcher::onMessage, dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
    
    // 设置服务器的消息处理回调函数
    // 当服务器收到任何消息时,都会调用dispatcher的onMessage方法
    server->setMessageCallback(message_cb);
    
    // 启动服务器,开始监听客户端连接和处理请求
    // 这是一个阻塞调用,服务器会一直运行直到被外部中断
    server->start();

    return 0;
}

我们有一个JSON-RPC服务器,当客户端发送一个RPC请求时,服务器端的处理流程如下:

  1. 服务器网络层接收到客户端的请求数据,将其解析为一个消息对象(比如RpcRequest),然后调用预先设置的消息回调函数(即Dispatcher的onMessage函数)。

  2. Dispatcher的onMessage函数被调用,它会根据消息的类型(MType)找到对应的处理器(Handler)。对于RPC请求,我们注册了处理RPC请求的处理器,即RpcRouter的onRpcRequest函数。

  3. RpcRouter的onRpcRequest函数被调用,它会根据请求中的方法名找到对应的用户回调函数(例如Add函数),然后调用该用户函数。

  4. 用户函数(Add)执行具体的业务逻辑,并返回结果。

  5. 然后,结果被封装成RPC响应,通过连接发送回客户端。

具体来说,回调函数的调用顺序如下:

  1. 服务器网络层(Server)在接收到一个完整的消息后,会调用我们设置的消息回调函数,即:message_cb,而message_cb绑定了Dispatcher::onMessage。

  2. 在Dispatcher::onMessage中,根据消息类型(这里是REQ_RPC)找到注册的处理器,即我们注册的cb,而cb绑定了RpcRouter::onRpcRequest。所以接下来调用RpcRouter::onRpcRequest。

  3. 在RpcRouter::onRpcRequest中,根据请求的方法名(比如"Add")找到注册的方法描述,其中包含了用户回调函数(即Add函数)。然后调用Add函数。

  4. Add函数执行加法运算,并将结果设置到rsp参数中。

  5. 然后,RpcRouter::onRpcRequest将Add函数的结果封装成一个RPC响应消息,并通过连接发送回客户端。

所以,回调链是:

Server网络层 → Dispatcher::onMessage → RpcRouter::onRpcRequest → 用户函数(Add)

每个函数的作用:

  1. Dispatcher::onMessage:这是一个消息分发函数,它根据消息类型将消息分发给对应的处理器。在这个例子中,它负责将RPC请求消息分发给RpcRouter::onRpcRequest。

  2. RpcRouter::onRpcRequest:这是一个RPC请求处理函数,它负责解析RPC请求,根据方法名调用对应的用户函数,并将用户函数的返回值封装成RPC响应。

  3. Add:用户定义的业务函数,执行具体的业务逻辑(这里是加法运算)。

注意:服务器网络层接收和解析消息的过程是自动的,由网络框架完成,我们只需要设置一个回调函数(message_cb)来处理解析好的消息即可。

二.同步请求客户端代码编写

client1.cpp

cpp 复制代码
// 引入必要的头文件
#include "../../common/message.hpp"       // 消息相关的基类和定义
#include "../../common/net.hpp"           // 网络通信相关的类和工厂
#include<thread>                         // 线程库,但在此代码中未使用
#include "../../common/dispatcher.hpp"    // 消息分发器
#include "../../client/requestor.hpp"     // 客户端请求器
#include"../../client/rpc_caller.hpp"     // RPC调用器

// main函数:程序入口点
int main()
{
    // 创建请求器实例,用于管理请求和响应的匹配
    auto requestor = std::make_shared<jsonRpc::client::Requestor>();
    
    // 创建RPC调用器实例,需要传入请求器作为参数
    auto caller = std::make_shared<jsonRpc::client::RpcCaller>(requestor);
    
    // 创建消息分发器实例,用于根据消息类型将消息分发到相应的处理器
    auto dispatcher = std::make_shared<jsonRpc::Dispatcher>();
    
    // 创建一个回调函数,当收到RPC响应消息时,调用请求器的onResponse方法进行处理
    // std::bind将Requestor::onResponse方法与requestor对象绑定
    // std::placeholders::_1和_2分别代表连接对象和消息对象参数
    auto cb = std::bind(&jsonRpc::client::Requestor::onResponse, requestor.get(), 
                        std::placeholders::_1, std::placeholders::_2);
    
    // 将回调函数注册到分发器中,当收到RSP_RPC类型的消息时,调用此回调
    // RSP_RPC表示RPC响应消息类型
    dispatcher->registerHandler<jsonRpc::BaseMessage>(jsonRpc::MType::RSP_RPC, cb);
    
    // 创建一个JSON-RPC客户端实例,连接到127.0.0.1:9090服务器
    // ClientFactory::create是一个静态工厂方法,用于创建客户端实例
    auto client = jsonRpc::ClientFactory::create("127.0.0.1", 9090);
    
    // 创建消息处理回调函数,将客户端收到的所有消息转发给分发器处理
    auto message_cb = std::bind(&jsonRpc::Dispatcher::onMessage, dispatcher.get(), 
                                std::placeholders::_1, std::placeholders::_2);
    
    // 设置客户端的消息处理回调函数
    // 当客户端收到任何消息时,都会调用dispatcher的onMessage方法
    client->setMessageCallback(message_cb);
    
    // 连接到服务器
    client->connect();
    
    // 获取客户端的连接对象,用于后续的RPC调用
    auto conn = client->connection();
    
    // 准备RPC调用所需的参数和接收结果的变量
    Json::Value params, result;
    params["num1"] = 11;  // 设置第一个参数num1为11
    params["num2"] = 22;  // 设置第二个参数num2为22
    
    // 调用RPC方法"Add",传递参数params,并接收结果到result中
    // caller->call会发送RPC请求并等待响应(同步调用)
    bool ret = caller->call(conn, "Add", params, result);
    
    // 检查调用是否成功
    if (ret != false)  // 注意:这里应该写 ret == true 更清晰,但保持原代码逻辑
    {
        // 打印计算结果
        std::cout << "result:" << result.asInt() << std::endl;
    }
    
    // 关闭客户端连接
    client->shutdown();
    
    // 程序正常结束,返回0
    return 0;
}

当客户端收到服务器发来的消息时,会触发客户端的消息回调函数。在这个例子中,客户端的消息回调函数被设置为dispatcher->onMessage。

因此,当客户端收到任何消息,都会调用dispatcher->onMessage。

在dispatcher->onMessage中,会根据消息的类型(MType)调用之前注册的对应类型的回调函数。这里,我们只为RSP_RPC类型注册了回调函数,即requestor->onResponse。

所以,当收到RPC响应消息时,调用链如下:

  • 客户端网络层收到数据,解析为消息,然后调用设置的回调函数dispatcher->onMessage。
  • dispatcher->onMessage根据消息类型(假设为RSP_RPC)找到之前注册的回调函数requestor->onResponse,并调用它。
  • requestor->onResponse函数会处理响应消息,比如将响应与之前发送的请求匹配,并设置相应的promise值(对于异步请求)或调用相应的回调函数。

但是,请注意,在这个例子中,我们使用的是同步调用caller->call。在同步调用中,caller->call内部会使用requestor发送请求,然后等待一个future,直到requestor->onResponse收到响应并设置promise的值,然后caller->call才会返回结果。

所以,在同步调用中,回调链的触发是由网络消息驱动的,但是调用线程会在caller->call内部阻塞,直到收到响应。

makefile(注意下面几个客户端都是使用这个makefile的)

bash 复制代码
CFLAG= -I ../../../build/release-install-cpp11/include/
LFLAG= -L ../../../build/release-install-cpp11/lib  -lmuduo_net -lmuduo_base -pthread -ljsoncpp
all: server client1 client2 client3
server: server.cpp
	g++  -g $(CFLAG) $^ -o $@ $(LFLAG)
client1: client1.cpp
	g++  -g $(CFLAG) $^ -o $@ $(LFLAG)
client2: client2.cpp
	g++  -g $(CFLAG) $^ -o $@ $(LFLAG)
client3: client3.cpp
	g++  -g $(CFLAG) $^ -o $@ $(LFLAG)
.PHONY: clean
clean: 
	rm -f server client1 client2 client3

那么我们直接运行一下看看

可以看到,非常的完美!!

三.异步请求客户端代码编写

这个其实总体代码和我们的同步请求客户端差不多,主要区别就是发送数据/接收数据的时候有一点小小的不同

cpp 复制代码
//使用future异步调用
    jsonRpc::client::RpcCaller::JsonAsyncResponse async_result;
    bool ret = caller->call(conn, "Add", params, async_result); // 异步调用,会将这个

    if (ret==true)
    {
        Json::Value result = async_result.get(); // 阻塞直到结果到达,事实上同步调用=异步调用+阻塞等待,阻塞等待那一步就是我们这里的get()
        //当然我这里是为了演示异步调用
        std::cout << "异步调用结果: " << result.asInt() << std::endl;
    }

我们看看完整代码

client2.cpp

cpp 复制代码
// 发送异步请求

// 引入必要的头文件
#include "../../common/message.hpp"    // 消息相关的基类和定义
#include "../../common/net.hpp"        // 网络通信相关的类和工厂
#include <thread>                      // 线程库,但在此代码中未使用
#include "../../common/dispatcher.hpp" // 消息分发器
#include "../../client/requestor.hpp"  // 客户端请求器
#include "../../client/rpc_caller.hpp" // RPC调用器
#include <future>

// main函数:程序入口点
int main()
{
    // 创建请求器实例,用于管理请求和响应的匹配
    auto requestor = std::make_shared<jsonRpc::client::Requestor>();

    // 创建RPC调用器实例,需要传入请求器作为参数
    auto caller = std::make_shared<jsonRpc::client::RpcCaller>(requestor);

    // 创建消息分发器实例,用于根据消息类型将消息分发到相应的处理器
    auto dispatcher = std::make_shared<jsonRpc::Dispatcher>();

    // 创建一个回调函数,当收到RPC响应消息时,调用请求器的onResponse方法进行处理
    // std::bind将Requestor::onResponse方法与requestor对象绑定
    // std::placeholders::_1和_2分别代表连接对象和消息对象参数
    auto cb = std::bind(&jsonRpc::client::Requestor::onResponse, requestor.get(),
                        std::placeholders::_1, std::placeholders::_2);

    // 将回调函数注册到分发器中,当收到RSP_RPC类型的消息时,调用此回调
    // RSP_RPC表示RPC响应消息类型
    dispatcher->registerHandler<jsonRpc::BaseMessage>(jsonRpc::MType::RSP_RPC, cb);

    // 创建一个JSON-RPC客户端实例,连接到127.0.0.1:9090服务器
    // ClientFactory::create是一个静态工厂方法,用于创建客户端实例
    auto client = jsonRpc::ClientFactory::create("127.0.0.1", 9090);

    // 创建消息处理回调函数,将客户端收到的所有消息转发给分发器处理
    auto message_cb = std::bind(&jsonRpc::Dispatcher::onMessage, dispatcher.get(),
                                std::placeholders::_1, std::placeholders::_2);

    // 设置客户端的消息处理回调函数
    // 当客户端收到任何消息时,都会调用dispatcher的onMessage方法
    client->setMessageCallback(message_cb);

    // 连接到服务器
    client->connect();

    // 获取客户端的连接对象,用于后续的RPC调用
    auto conn = client->connection();

    // 准备RPC调用所需的参数和接收结果的变量
    Json::Value params, result;
    params["num1"] = 11; // 设置第一个参数num1为11
    params["num2"] = 22; // 设置第二个参数num2为22

    //使用future异步调用
    jsonRpc::client::RpcCaller::JsonAsyncResponse async_result;
    bool ret = caller->call(conn, "Add", params, async_result); // 异步调用,会将这个

    if (ret==true)
    {
        Json::Value result = async_result.get(); // 阻塞直到结果到达,事实上同步调用=异步调用+阻塞等待,阻塞等待那一步就是我们这里的get()
        //当然我这里是为了演示异步调用
        std::cout << "异步调用结果: " << result.asInt() << std::endl;
    }

    // 关闭客户端连接
    client->shutdown();

    // 程序正常结束,返回0
    return 0;
}

我们直接编译运行看看

四.回调请求客户端代码编写

这个也是和上面的差不了太多,就是这个发送数据和接收数据的时候有点区别

cpp 复制代码
// 定义回调函数
    auto callback = [](const Json::Value& result) {
        std::cout << "回调函数接收到结果: " << result.asInt() << std::endl;
    };
    
    bool ret = caller->call(conn, "Add", params, callback);//使用回调函数调用
    
    if (ret==true)//调用成功
    {
        // 等待一段时间确保回调执行
        std::this_thread::sleep_for(std::chrono::seconds(2));
    }

当然,我们发现结果的处理,我们完全将它放到了这个回调函数里面去进行。

我们看看完整的代码

client3.cpp

cpp 复制代码
//发送回调调用

// 引入必要的头文件
#include "../../common/message.hpp"       // 消息相关的基类和定义
#include "../../common/net.hpp"           // 网络通信相关的类和工厂
#include<thread>                         // 线程库,但在此代码中未使用
#include "../../common/dispatcher.hpp"    // 消息分发器
#include "../../client/requestor.hpp"     // 客户端请求器
#include"../../client/rpc_caller.hpp"     // RPC调用器

// main函数:程序入口点
int main()
{
    // 创建请求器实例,用于管理请求和响应的匹配
    auto requestor = std::make_shared<jsonRpc::client::Requestor>();
    
    // 创建RPC调用器实例,需要传入请求器作为参数
    auto caller = std::make_shared<jsonRpc::client::RpcCaller>(requestor);
    
    // 创建消息分发器实例,用于根据消息类型将消息分发到相应的处理器
    auto dispatcher = std::make_shared<jsonRpc::Dispatcher>();
    
    // 创建一个回调函数,当收到RPC响应消息时,调用请求器的onResponse方法进行处理
    // std::bind将Requestor::onResponse方法与requestor对象绑定
    // std::placeholders::_1和_2分别代表连接对象和消息对象参数
    auto cb = std::bind(&jsonRpc::client::Requestor::onResponse, requestor.get(), 
                        std::placeholders::_1, std::placeholders::_2);
    
    // 将回调函数注册到分发器中,当收到RSP_RPC类型的消息时,调用此回调
    // RSP_RPC表示RPC响应消息类型
    dispatcher->registerHandler<jsonRpc::BaseMessage>(jsonRpc::MType::RSP_RPC, cb);
    
    // 创建一个JSON-RPC客户端实例,连接到127.0.0.1:9090服务器
    // ClientFactory::create是一个静态工厂方法,用于创建客户端实例
    auto client = jsonRpc::ClientFactory::create("127.0.0.1", 9090);
    
    // 创建消息处理回调函数,将客户端收到的所有消息转发给分发器处理
    auto message_cb = std::bind(&jsonRpc::Dispatcher::onMessage, dispatcher.get(), 
                                std::placeholders::_1, std::placeholders::_2);
    
    // 设置客户端的消息处理回调函数
    // 当客户端收到任何消息时,都会调用dispatcher的onMessage方法
    client->setMessageCallback(message_cb);
    
    // 连接到服务器
    client->connect();
    
    // 获取客户端的连接对象,用于后续的RPC调用
    auto conn = client->connection();
    
    // 准备RPC调用所需的参数和接收结果的变量
    Json::Value params, result;
    params["num1"] = 11;  // 设置第一个参数num1为11
    params["num2"] = 22;  // 设置第二个参数num2为22
    
    // 定义回调函数
    auto callback = [](const Json::Value& result) {
        std::cout << "回调函数接收到结果: " << result.asInt() << std::endl;
    };
    
    bool ret = caller->call(conn, "Add", params, callback);//使用回调函数调用
    
    if (ret==true)//调用成功
    {
        // 等待一段时间确保回调执行
        std::this_thread::sleep_for(std::chrono::seconds(2));
    }
    
    // 关闭客户端连接
    client->shutdown();
    
    // 程序正常结束,返回0
    return 0;
}

也是相当的完美。

相关推荐
2401_865854882 小时前
ssl免费证书与收费证书有什么区别
网络·网络协议·ssl
奋斗者1号2 小时前
SSL/TLS认证流程与CA证书字段详解
网络协议·iphone·ssl
我在人间贩卖青春2 小时前
TCP编程核心API
网络·网络协议·tcp/ip
czy87874752 小时前
LwIP 提供了三种主要的 API 接口,分别针对不同的应用场景(如实时性、易用性、资源占用等),开发者可根据需求选择。
网络协议
梁辰兴2 小时前
计算机网络基础:用户数据报协议 UDP
网络·网络协议·计算机网络·udp·用户数据报协议·计算机网络基础·梁辰兴
老歌老听老掉牙3 小时前
Python+PyQt5 实现目录文件扫描与导出工具
python·qt·文件扫描
七夜zippoe3 小时前
HTTP协议深度解析与实现:从请求响应到HTTP/3的完整指南
python·网络协议·http·quic·帧结构
摆摊的豆丁3 小时前
FreeRTOS-Plus-TCP 协议支持与网络编程指南
网络·网络协议·tcp/ip·freertos
訫悦3 小时前
体验在Qt中简单使用C++20的协程
qt·c++20·协程