【Json-Rpc #1】项目背景及环境搭建

在这里插入图片描述

📃个人主页:island1314

🔥个人博客:island

⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞

  • 生活总是不会一帆风顺,前进的道路也不会永远一马平川,如何面对挫折影响人生走向 – 《人民日报》

🔥 目录

    • 一、项目介绍
    • 二、技术选型
      • 2.1 RPC 实现方案
      • 2.2 网络传输的参数和返回值怎么映射到对应的RPC接口上?
        • 方法一:使用 protobuf 的反射机制
        • 方法二:使用 C++ 模板、类型萃取、函数萃取等机制
        • 方法三:使用更通用的类型(如 JSON)
        • 🌈 技术方案对比
      • 2.3 网络传输怎么做?
      • 2.4 序列化和反序列化?
    • 三、环境搭建
      • 3.1 Centos 7.6 环境搭建
      • 3.2 Ubuntu 22.04 环境搭建


一、项目介绍

🔥 RPC(Remote Procedure Call)远程过程调用,是一种通过网络从远程计算机上请求服务,而不需要了解底层网络通信细节。

  • RPC 可以使用多种网络协议进行通信,如HTTP、TCP、UDP等,并且在 TCP/IP 网络四层模型中跨越了传输层和应用层。简言之RPC就是像调用本地方法一样调用远程方法
  • 过程可以理解为业务处理、计算任务,更直白的说,就是程序/方法/函数等,就是像调用本地方法一样调用远程方法

image-20250312152552022

💬 通俗类比:通信方式的进化

+ 本地调用:情侣同城约会- 随时见面(低延迟)- 直接交流(无需协议)+ RPC调用:跨国网恋奔现  ✈️ 约定时间(服务发现)📨 发送航班信息(序列化)🛃 海关检查(协议校验)💌 最终见面(反序列化)

一个完整RPC通信框架,大概包含以下内容

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

我们的项目是基于C++、JsonCpp、muduo网络库实现一个简单、易用的RPC通信框架,即使是不懂网络的开发者也可以很快速的上手,它实现了同步调用、异步callback 调用、异步 futrue调用、服务注册/发现,服务上线/下线以及发布订阅等功能设计。

二、技术选型

2.1 RPC 实现方案

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

  1. clientserver 继承公共接口

    • 根据 IDL(接口描述语言)定义公共接口
    • 编写代码生成器根据IDL语言生成相关的C++、Java代码然后我们的客户端和服务器程序共同向上继承公共接口即可
    • 比如:我们常用的Protobuf、ison可以定义IDL接口,并生成RPC相关的代码
    • 缺点:使用pb因为生成一部分代码,所以对理解不够友好;如果是json定义IDL语言 需要自己编写代码生成器难度较大一点,暂不考虑这种方案
  2. 实现⼀个远程调用接口cal,,然后通过传入函数名参数来调用RPC接口,我们采用这种实现方案

image-20250312154155524

2.2 网络传输的参数和返回值怎么映射到对应的RPC接口上?

方法一:使用 protobuf 的反射机制

原理

protobuf 是一种高效的序列化协议,支持通过 .proto 文件定义数据结构。protobuf 提供了反射机制,允许程序在运行时动态获取消息的字段信息(如字段名、类型等)。通过反射机制,可以将网络传输的参数和返回值动态映射到对应的RPC接口。

实现步骤

  1. 定义 .proto 文件 :描述RPC接口的请求和响应数据结构。
  2. 生成代码 :使用 protoc 工具生成对应语言的代码(如C++、Python等)。
  3. 利用反射机制 :
    • 在运行时,通过反射机制解析请求和响应的字段。
    • 动态调用对应的RPC接口,并将解析后的数据作为参数传递。
  4. 序列化和反序列化 :将请求和响应数据序列化为二进制格式进行传输。

优点

  • 高效:protobuf 序列化效率高,占用带宽小。
  • 强类型:编译时检查字段类型,减少运行时错误。
  • 易扩展:通过 .proto 文件轻松扩展字段。

缺点

  • 学习成本较高:需要熟悉 .proto 文件和反射机制。
  • 动态性有限:反射机制虽然灵活,但仍需依赖预定义的 .proto 文件。

Mermaid

Client Server ProtoReflection 定义.proto文件并生成代码 提供反射接口 序列化请求数据(protobuf) 反序列化请求数据 使用反射解析字段 调用对应RPC接口 序列化响应数据 返回响应数据 Client Server ProtoReflection

方法二:使用 C++ 模板、类型萃取、函数萃取等机制

原理

C++ 模板元编程允许在编译时对类型进行操作,而类型萃取和函数萃取则用于提取函数的参数和返回值类型。通过这些机制,可以在编译时自动推导出RPC接口的参数和返回值类型,从而实现参数和返回值的映射。

实现步骤

  1. 定义RPC接口 :使用C++函数定义RPC接口。
  2. 使用模板萃取 :
    • 利用 std::function 或模板函数提取函数的参数和返回值类型。
    • 定义通用的包装器(Wrapper),将参数和返回值映射到网络传输的格式。
  3. 序列化和反序列化 :
    • 将参数序列化为网络传输格式(如JSON或自定义二进制格式)。
    • 在服务端反序列化后,调用对应的RPC接口。
  4. 返回结果 :将返回值序列化并发送回客户端。

优点

  • 高性能:所有类型推导和映射在编译时完成,运行时开销低。
  • 灵活性强:支持任意类型的参数和返回值。
  • 类型安全:编译时检查参数和返回值类型。

缺点

  • 复杂度高:需要熟悉C++模板元编程和类型萃取机制。
  • 不易调试:模板代码在编译时展开,调试难度较大。

MerMaid

Client Server TemplateMechanism 定义RPC接口 提取参数和返回值类型 序列化请求数据(JSON/自定义格式) 反序列化请求数据 调用对应RPC接口 序列化响应数据 返回响应数据 Client Server TemplateMechanism
方法三:使用更通用的类型(如 JSON)

原理

JSON 是一种轻量级的数据交换格式,具有良好的可读性和跨语言支持。通过设计一套通用的参数和返回值协议,可以将网络传输的数据统一表示为JSON格式,从而简化参数和返回值的映射。

实现步骤

  1. 设计协议 :
    • 定义请求和响应的JSON结构,包括字段名、类型和含义。
    • 例如,请求可能包含 method(接口名)、params(参数列表)等字段。
  2. 序列化和反序列化 :
    • 客户端将参数序列化为JSON格式并发送。
    • 服务端解析JSON数据,提取参数并调用对应的RPC接口。
  3. 返回结果 :
    • 服务端将返回值序列化为JSON格式并发送回客户端。

优点

  • 简单易用:JSON格式直观,易于理解和实现。
  • 跨语言支持:几乎所有的编程语言都支持JSON解析。
  • 动态性强:无需提前定义固定的数据结构。

缺点

  • 性能较低:JSON序列化和反序列化效率低于二进制格式。
  • 类型不安全:JSON是弱类型格式,可能导致运行时错误。

MerMaid

Client Server JSONProtocol 设计请求和响应协议 序列化请求数据为JSON 发送JSON请求 解析JSON请求 调用对应RPC接口 序列化响应数据为JSON 返回JSON响应 Client Server JSONProtocol
🌈 技术方案对比
方案核心技术优点缺点
Protobuf反射利用.proto文件的元数据描述强类型安全,跨语言支持需要IDL编译,C++实现较复杂
模板元编程类型萃取+函数签名解析零运行时开销,类型严格匹配代码可读性差,调试困难
JSON通用协议动态类型系统+预定义协议格式开发简单,易扩展,可视化调试类型安全性需运行时校验
  • 由于前两种技术难度和学习成本较高,因此这个项目我们使用第三种方式

2.3 网络传输怎么做?

  • 原生socket :实现难度较大,暂不考虑
  • Boost asio库的异步通信:需要扩展boost库
  • muduo库:和当前项目对应,学习开发成本较低

2.4 序列化和反序列化?

  • Protobuf:可选
  • JSON:因为项目需要使用 JSON 来定义函数参数和返回值,所以项目中直接采用 JSON 进行序列化和反序列化

三、环境搭建

3.1 Centos 7.6 环境搭建

① 安装 wget

sudo yum install wget

② 更新软件源

sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.reposudo yum clean all # 清理缓存信息
sudo yum makecache

③ 安装 scl 软件源

sudo yum install centos-release-scl-rh centos-release-scl

④ 安装 epel 软件源

sudo yum install epel-release

⑤ 安装 lrzsz 传输工具

sudo yum install lrzsz
rz --version
rz (lrzsz) 0.12.20

⑥ 安装高版本 gcc/g++ 编译器

sudo yum install devtoolset-7-gcc devtoolset-7-gcc-c++
echo "source /opt/rh/devtoolset-7/enable" >> ~/.bashrc
source ~/.bashrc
g++ -v

⑦ 安装 Jsoncpp 库

sudo yum install jsoncpp-devells /usr/include/jsoncpp/json/
assertions.h autolink.h config.h ...

⑧ 安装 cmake

sudo yum install cmakecmake --version
cmake version 2.8.12.2

⑨ 安装 Muduo

  • 下载源码
# git⽅式
[zsc@node ~]$ git clone https://github.com/chenshuo/muduo.git
  • 修复 muduo 库 安装 protorpc 的时候没有安装
/muduo-master/muduo/net/protorpc/CMakeLists.txt
  • 安装依赖环境
sudo yum install make boost-devel

当前上面步骤还是过于多了,我们可以直接 运行脚本编译安装

脚本链接:https://gitee.com/qigezi/bitrpc/blob/master/third/muduo-master.zip

然后把脚本下载之后导入解包,按照下面指令编译安装即可

./build.sh
./build.sh install

3.2 Ubuntu 22.04 环境搭建

① 安装 wget – 一般默认情况下都有

sudo apt-get install wget

② 更新国内软件源

先备份原来的 /etc/apt/source.list 文件

sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak# 比如
lighthouse@VM-8-10-ubuntu:~$ sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
lighthouse@VM-8-10-ubuntu:~$ ls /etc/apt/
apt.conf.d   keyrings       sources.list      sources.list.curtin.old  trusted.gpg.d
auth.conf.d  preferences.d  sources.list.bak  sources.list.d

添加软件源文件内容,新增以下内容

# 先打开源文件
sudo vi /etc/apt/source.listdeb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
#添加清华源 
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse

新增完毕后,更新源

sudo apt-get update

③ 安装 lrzsz 传输工具

sudo apt-get install lrzsz
rz --version
rz (lrzsz) 0.12.20

④ 安装高版本 gcc/g++ 编译器

sudo apt-get install gcc g++

⑤ 安装项目构建工具 make 和 cmake

sudo apt-get install makesudo apt-get install cmake
cmake --version
cmake version 3.22.1

⑥ 安装调试器 gdb

sudo apt-get install gdb

⑦ 安装 git

sudo apt-get install git
git --versio

⑧ 安装 Jsoncpp 库

sudo apt-get install libjsoncpp-dev# 安装成功之后
ls /usr/include/jsoncpp/json/
allocator.h   config.h    json_features.h  reader.h  version.h
assertions.h  forwards.h  json.h           value.h   writer.h

⑨ 安装 Muduo

  • 下载源码
# git⽅式
[zsc@node ~]$ git clone https://github.com/chenshuo/muduo.git
  • 安装依赖环境
sudo apt-get install libz-dev libboost-all-dev

运行脚本编译安装

unzip muduo-master.zip
./build.sh
./build.sh install

参考

https://zhuanlan.zhihu.com/p/460646015

https://zhuanlan.zhihu.com/p/33298916

源码:https://github.com/cinemast/libjson-rpc-cpp

      value.h   writer.h

⑨ 安装 Muduo- 下载源码 ```bash
# git⽅式
[zsc@node ~]$ git clone https://github.com/chenshuo/muduo.git
  • 安装依赖环境
sudo apt-get install libz-dev libboost-all-dev

运行脚本编译安装

unzip muduo-master.zip
./build.sh
./build.sh install

参考

https://zhuanlan.zhihu.com/p/460646015

https://zhuanlan.zhihu.com/p/33298916

源码:https://github.com/cinemast/libjson-rpc-cpp

源码:https://github.com/qicosmos/rest_rpc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/77322.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF轮播图动画交互 动画缩放展示图片

WPF轮播图动画交互 动画缩放展示图片 效果如下图&#xff1a; XAML代码&#xff1a; <Window x:Class"Caroursel.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/20…

为什么 npm list -g 没显示 node_modules?✨

揭秘&#xff1a;为什么 npm list -g 没显示 node_modules&#xff1f;&#x1f575;️‍♂️✨ 嗨&#xff0c;各位代码探险家&#xff01;&#x1f44b; 今天我们要破解一个 npm 小谜团&#xff1a;运行 npm list -g --depth0 时&#xff0c;为什么输出的路径里看不到 node_…

都江堰与郑国渠

目录标题 一、历史背景&#xff1a;地缘博弈下的水利突围都江堰&#xff1a;化水患为天府的千年大计郑国渠&#xff1a;间谍引发的战略反转 二、工程智慧&#xff1a;超越时代的科技奇迹都江堰&#xff1a;生态治水的典范郑国渠&#xff1a;泥沙资源化的创举 三、后世影响&…

链路聚合+vrrp

1.链路聚合 作用注意事项将多个物理接口&#xff08;线路&#xff09;逻辑上绑定在一起形成一条逻辑链路&#xff0c;起到叠加带宽的作用1.聚合接口必须转发速率一致。2.聚合设备两端必须一致 配置命令 方法一 [Huawei]interface Eth-Trunk 0----先创建聚合接口&#xff0c;…

【STM32单片机】#7 定时器输入捕获

主要参考学习资料&#xff1a; B站江协科技 STM32入门教程-2023版 细致讲解 中文字幕 开发资料下载链接&#xff1a;https://pan.baidu.com/s/1h_UjuQKDX9IpP-U1Effbsw?pwddspb 单片机套装&#xff1a;STM32F103C8T6开发板单片机C6T6核心板 实验板最小系统板套件科协 实验&…

【android bluetooth 框架分析 01】【关键线程 3】【bt_jni_thread 线程介绍】

1. bt_jni_thread 职责介绍 bt_jni_thread 这个线程的作用是专门负责处理蓝牙 JNI 层的消息循环&#xff0c;也可以说是 C 层和 Java 层交互的桥梁线程。 1.1 什么是 JNI 层&#xff1f;为什么需要这个线程&#xff1f; JNI&#xff08;Java Native Interface&#xff09;是 …

基于视觉语言模型的机器人实时探索系统!ClipRover:移动机器人零样本视觉语言探索和目标发现

作者&#xff1a;Yuxuan Zhang 1 ^{1} 1, Adnan Abdullah 2 ^{2} 2, Sanjeev J. Koppal 3 ^{3} 3, and Md Jahidul Islam 4 ^{4} 4单位&#xff1a; 2 , 4 ^{2,4} 2,4佛罗里达大学电气与计算机工程系RoboPI实验室&#xff0c; 1 , 3 ^{1,3} 1,3佛罗里达大学电气与计算机工程系F…

SpringBoot和微服务学习记录Day2

微服务 微服务将单体应用分割成更小的的独立服务&#xff0c;部署在不同的服务器上。服务间的关联通过暴露的api接口来实现 优点&#xff1a;高内聚低耦合&#xff0c;一个模块有问题不影响整个应用&#xff0c;增加可靠性&#xff0c;更新技术方便 缺点&#xff1a;增加运维…

网站集群批量管理-Ansible剧本与变量

复盘内容&#xff1a;链接指北 查看ansible命令文档 ansible-doc -s systemd一、剧本 何为剧本: playbook 文件,用于长久保存并且实现批量管理,维护,部署的文件. 类似于脚本存放命令和变量 剧本yaml格式,yaml格式的文件:空格,冒号. 剧本未来我们批量管理,运维必会的内容. …

如何在Dify中安装运行pandas、numpy库(离线、在线均支持,可提供远程指导)

pandas和numpy这两个库是数据科学和数据分析中经常使用的工具包&#xff0c;原生的Dify无法直接使用这两个库&#xff0c;需要手动安装后才可以使用。本文将介绍如何在Dify中安装pandas和numpy&#xff0c;并在代码执行节点中运行使用pandas和numpy。 Dify的代码执行节点中的py…

Helm核心概念与常见操作介绍

在管理Kubernetes集群里的应用时&#xff0c;Helm能帮上大忙&#xff0c;它把应用的部署、升级和管理变得简单多了&#xff0c;有如是Kubernetes的 “应用商店”。 Helm的三个重要概念 三大概念最直接的理解&#xff1a;Helm 安装 charts 到 Kubernetes 集群中&#xff0c;每…

rkmpp 解码 精简mpi_dec_test.c例程

rkmpp 解码流程&#xff08;除 MPP_VIDEO_CodingMJPEG 之外&#xff09; 源码 输入h264码流 输出nv12文件 /** Copyright 2015 Rockchip Electronics Co. LTD** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file exce…

用一个实际例子快速理解MCP应用的工作步骤

已经有很多的文章介绍MCP server&#xff0c;MCP Client工作原理&#xff0c;这里不做太多介绍。但是很多介绍都只是侧重介绍概念&#xff0c;实际的工作原理理解起来对初学者还是不太友好。本文以一个智能旅游咨询系统为例&#xff0c;详细说明在利用 Model Context Protocol&…

【LeetCode 题解】数据库:1321.餐馆营业额变化增长

一、问题描述 本题给定了一个名为 Customer 的表&#xff0c;记录了餐馆顾客的交易数据&#xff0c;包括顾客 ID、姓名、访问日期和消费金额。作为餐馆老板&#xff0c;我们的任务是分析营业额的变化增长情况&#xff0c;具体来说&#xff0c;就是计算以 7 天&#xff08;某日…

【Python】读取xlsb或xlsx的单一或连续单元格工具类

代码主要来自Kimi.ai&#xff0c;有修改。 优先使用工作表序号索引工作表&#xff0c;序号从1开始。 运行需要先安装openpyxl和pyxlsb两个第三方库。 import openpyxl from openpyxl.utils import range_boundaries from pyxlsb import open_workbook as open_xlsbclass Exc…

【蓝桥杯】动态规划:背包问题

这篇文章主要记录动态规划方面的学习。 动态规划的核心思想: 把大问题分解成小问题,记住小问题的解,避免重复计算。 动态规划(DP)的三大特点: ①最优子结构:大问题的最优解可以由小问题的最优解推导出来 ②重叠子问题:在求解过程中会反复遇到相同的小问题 ③无后效…

华为数字芯片机考2025合集1已校正

单选 1&#xff0e;以下低功耗措施中&#xff0c;哪种不是降低电路翻转率的方法? A.在不进行算术运算的时候&#xff0c;使这些模块的输入保持不变&#xff0c;不让新的操作数进来 B.采用Gray 码或One‐hot 码作为状态机编码 C.减少电路中的glitch D.重新安排“if‐else”表达…

React 列表渲染

开发环境&#xff1a;Reacttsantd 你可能经常需要通过 JavaScript 的数组方法 来操作数组中的数据&#xff0c;从而将一个数据集渲染成多个相似的组件。在这篇文章中&#xff0c;你将学会如何在 React 中使用 filter() 筛选需要渲染的组件和使用 map() 把数组转换成组件数组。 …

力扣刷题DAY11(动态规划-线性DP)

一、最长上升子序列 300. 最长递增子序列 &#xff08;一&#xff09;初版代码 class Solution { public:int lengthOfLIS(vector<int>& nums) {int n nums.size();vector<int> f(n 1, 1); //初始化为1&#xff0c;因为每个数至少可以作为一个单独的序列in…

DFS--

数字的全排列 #include <bits/stdc.h> using namespace std;//最大的排列数目 const int N10; int n; //存储排列的路径 int path[N]; //标记数字是否已经被使用 bool st[N];void dfs(int u){//到达递归边界&#xff0c;输出一个排列if(un){//输出循环for(int i0; i<…