当前位置: 首页 > news >正文

【C++】Json-Rpc框架项目介绍(1)

项目介绍

RPC(Remote Procedure Call)即远程过程调用,是一种通过网络从远程计算机程序中请求服务而不需要了解底层网络实现细节的一种 协议
RPC(Remote Procedure Call)可以使用多种网络协议进行通信,如 HTTP 、TCP 、UDP等。就像调用本地方法一样调用远程方法。

RPC框架

  • 序列化协议
  • 通信协议
  • 连接复用
  • 服务注册
  • 服务发现
  • 服务订阅和通知
  • 负载均衡
  • 服务监控
  • 同步调用
  • 异步调用

技术选型

目前RPC的实现方案主要有两种:

    • client和server继承公共接口:
    • 根据IDL(接口描述语言)定义公共接口
    • 编写代码生成器根据 IDL 语言生成相关的C++、Java代码
    • 客户端和服务器向上继承公共接口
    • 缺点:使用Protobuf、json可以定义IDL接口,并生成RPC相关代码,其中Protobuf需要通过protoc生成强类型代码,灵活性受限,且对理解不友好,如果用Json定义IDL语言,需要自己编写代码生成器,难度较大,暂不考虑这种方案
  • 实现一个远程调用接口call,然后传入函数名参数来调用RPC接口,我们采用这种方案

  • 网络传输的参数和返回值映射到对应RPC接口上:
    使用JSON类型,设计好参数和返回值协议

  • 网络传输:
    使用muduo库来实现网络传输

  • 序列化和反序列化
    使用JSON来实现

开发环境LInux

  • Linux (Centos-7.6 / Ubuntu6.4)
  • Vscode / Vim
  • g++ / gdb
  • Makefile

Muduo库

muduo是是由陈硕大佬开发,是一个基于 非阻塞IO事件驱动 的C++高并发TCP网络编程库。它是一款基于主从Reactor模型的网络库,其使用的线程模型是 one loop per thread

  • 一个线程只能有一个事件循环,用于响应计时器和IO时间
  • 一个文件描述符只能由一个线程进行读写,也就是一个TCP连接必须归属于某个EventLoop

C++11异步操作

std::future

std::future是C++11标准库中的一个模版类,它表示一个 异步操作的结果 ,当我们在多线程编程中使用异步任务时,std::future可以帮助我们在需要的时候获取任务的执行结果。它的一个主要特性就是能够阻塞当前线程,直到异步操作完成,确保我们在获取结果时不会遇到未完成的操作。
应用场景:

  • 异步任务:当我们在后台执行一些耗时操作时,如网络请求和计算密集型任务等,std::future可以表示异步执行的结果。通过创建新线程执行任务,实现任务的并行处理,提高程序的效率
  • 并发控制:我们可以通过使用std::future是线程之间的同步,确保任务完成后再获取结果并继续执行后续操作
  • 结果获取:std::future提供了一种安全的方式来获取异步任务的结果,我们可以使用 std::future::get()函数来获取异步任务的执行结果,并且这个函数会阻塞当前线程,直到异步操作完成,确保后序操作在结果获取后执行,同时保证了线程之间的同步。

std::async

std::async 是一种将任务与 std::future 关联的方法,它创建并运行一个异步任务,并返回一个与任务关联的 future 对象。
其中 std::async 是否启动一个新线程,或者在等待 futrue 时,任务是否同步运行都取决于你给的参数 std::launch:

  • std::launch::deferred 表明该函数会被延迟调用,直到调用 get() 或者 wait() 才会开始执行任务
  • std::launch::async表示函数会在自己创建的线程上面运行
  • std::launch::deferred | std::launch::async 取决于系统内部的资源的自动决策,当高资源可用时,采用 std::launch::async ,创建新线程实现并发,相反,则采std::launch::deferred 策略,在调用线程上执行,避免资源竞争和崩溃风险。
示例代码
#include <iostream>
#include <future>
#include <chrono>std::string async_task()
{std::cout << "任务执行中" << std::endl;return "获取成功";
}int main()
{std::future<std::string> result = std::async(std::launch::deferred,async_task);std::this_thread::sleep_for(std::chrono::seconds(10));std::cout << "任务在等待10s后再执行" << std::endl;std::string name = result.get();std::cout << name << std::endl;return 0;
}

结果:

任务在等待10s后再执行
任务执行中
获取成功
std::string async_task()
{std::cout << "任务正在执行" << std::endl;return "获取成功";
}int main()
{std::future<std::string> result = std::async(std::launch::async,async_task);std::this_thread::sleep_for(std::chrono::seconds(10));std::string name = result.get();std::cout << name << std::endl;return 0;
}

结果:

任务正在执行
获取成功

std::packaged_task

std::packaged_task就是将任务和 std::future 绑定在一起的模版,是一种对任务的封装,我们可以通过std::packaged_task对象获取任务相关联的std::future对象,通过调用 get_future() 方法获得。std::packaged_task的模版参数是函数签名。
可以把std::futurestd::async 看成是分开的,而std::packaged_task则是一个整体

示例代码
#include <iostream>
#include <future>
#include <thread>
#include <utility>std::string async_task() 
{std::cout << "任务执行中" << std::endl;return "获取成功";
}int main() 
{// 1. 创建 packaged_task 并获取 futurestd::packaged_task<std::string()> task(async_task);std::future<std::string> result = task.get_future();// 2. 将任务移动到新线程中异步执行std::thread t(std::move(task));t.detach();  // 或 t.join()// 3. 获取结果(阻塞直到任务完成)std::string name = result.get();  // 若任务未执行会在此阻塞std::cout << name << std::endl;return 0;
}

结果:

任务执行中
获取成功

std::promise

std::promise提供了一种设置值的方式,它可以在设置之后通过相关联的 std::futrue对象进行读取。其实就是之前std::futrue需要等待异步函数的返回值,但std::promise提供了一种手动方式让std::futrue就绪

示例代码
void task(std::promise<int> promise_result)
{int result = 2;std::cout << "task result: " << result << std::endl;std::this_thread::sleep_for(std::chrono::seconds(5));promise_result.set_value(result);
}int main()
{std::promise<int> promise_result;std::future<int> future_result = promise_result.get_future();std::thread task_thread(task,std::move(promise_result));task_thread.detach();std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "执行其他操作" << std::endl;int result = future_result.get();std::cout << "result: " << result << std::endl;return 0;
}

结果:

task result: 2
执行其他操作
result: 2

相关文章:

  • Agent框架LangGraph:实现一个简单的Plan-and-Execute Agent
  • 电子电器架构 --- 面向下一代车辆的演进式(发展演变的)汽车网关
  • 仅追加KV数据库
  • 实验一 进程控制实验
  • 2023蓝帽杯初赛内存取证-4
  • NVIDIA 自动驾驶技术见解
  • 从零到多智能体:Google Agent开发套件(ADK)入门指南
  • C语言教程(十三):C 语言中 enum(枚举)的详细介绍
  • 武装Burp Suite工具:RouteVulScan插件_被动扫描发现漏洞.
  • shared_ptr八股收集 C++
  • SwiftInfer —— 大模型无限流式输入推理打破多轮对话长度限制
  • 【题解-Acwing】847. 图中点的层次
  • 双指针之有序数组的平方
  • 航电系统之自动控制系统篇
  • MulanPSL-1.0开源协议
  • 衡石ChatBI:依托开放架构构建技术驱动的差异化数据服务
  • 该虚拟机似乎正在使用中。如果该虚拟机未在使用,请按“获取所有权(T)”按钮获取它的所有权。否则,请按“取消(C)”按钮以防损坏解决方法
  • VSCode中安装GitGraph
  • 3.6/Q1,Charls数据库经典文章解读
  • Python设计模式:对象池
  • 载人登月总体进展顺利
  • 佩索阿稳定常销,陀翁不断加印,青少年喜欢黑塞
  • 华天酒店:2024年归母净亏损约1.81亿元,已连续亏损3年
  • 打造“朋友圈”,“淘书乐”为旧书找“新朋友”
  • 关税战推高成本,美澳“奥库斯”核潜艇协议或将生变
  • 上海明天有雷雨、大风,下周气温在春日舒适区间