当前位置: 首页 > 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
http://www.xdnf.cn/news/89623.html

相关文章:

  • 审计平台本地部署遇到的坑
  • 三生原理与现有密码学的核心区别?
  • 龙虎榜——20250422
  • Airbyte - 数据集成平台
  • vue 修改路由动态选择路由 改文件位置
  • 用Qt和deepseek创建自己的问答系统
  • transformer 编码器层
  • 聊天交友APP聊天系统框架搭建
  • 【Linux禁用历史命令】
  • RK3588 Buildroot 新建板级DTS
  • JAVA线程池ThreadPoolExecutor说明
  • 树莓派超全系列教程文档--(40)树莓派config.txt旧版GPIO控制、超频及条件过滤器
  • 【Spring】依赖注入的方式:构造方法、setter注入、字段注入
  • ProxySQL如何支持高并发读写请求
  • ubuntu 安装 redis server
  • 技术能力和关系比较实在没有可比性
  • 【同轴线共焦传感器原理】
  • Tree Shaking 原理
  • [原创](现代Delphi 12指南):[macOS 64bit App开发]:在Mac App Store外创建、部署与公证
  • 【AI面试】分类模型 之 随机森林
  • UWB定位技术在钢铁厂行业中的创新应用与价值实践
  • Linux:简单自定义shell
  • Unity使用反射进行Protobuf(CS/SC)协议,json格式_002
  • Python 常用Web框架对比
  • 乐视系列玩机---乐视2 x620 x628等系列线刷救砖以及刷写第三方twrp 卡刷第三方固件步骤解析
  • Spring 中 @Component, @Repository, @Service的区别
  • 电商场景下Elasticsearch集群与分片(Sharding)的ELK安装配置指南
  • qemu如何支持vpxor %xmm0,%xmm0,%xmm0(百度AI)
  • ACI multipod 一、组网概要
  • 【自然语言处理与大模型】如何知道自己部署的模型的最大并行访问数呢?