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

[实现Rpc] 服务端 | RpcRouter实现 | Builder模式

目录

项目服务端独用类的实现

1. RpcRouter类的实现

ServiceDescribe

SDescribeFactory

⭕ Builder模式

1. 动机

2. 模式定义

3. 要点总结

4. 代码感受

ServiceManager

RpcRouter

4. 代码感受

ServiceManager

RpcRouter


前文我们就将 Rpc 通用类都实现完啦,接下来我们继续~

回忆:Rpc 作用:

  • 调用 服务端的算力 来解决 客户端请求的问题

项目服务端独用类的实现

1. RpcRouter类的实现

(1)主要的功能:

  • 提供Rpc请求处理回调函数。(含 检查操作)
  • 内部的服务管理。
    • 方法名称。
    • 参数信息。
    • 对外提供参数校验接口。

相当于 是在 client 和 server 之间,除了 dipatcher 又套了一层 server

(2)具体实现:

框架 搭建:

#pragma once
#include "../common/dispatcher.hpp"
#include "../common/message.hpp"
#include <vector>using namespace bitrpc;namespace server
{// 嵌套一层 server 命名空间,避免和client 部分接口 重合;enum class VType{BOOL = 0,INTEGRAL,NUMERIC,STRING,ARRAY,OBJECT,};class ServiceDescribe{public:using ptr=std::shared_ptr<ServiceDescribe>;using ServiceCallback=std::function<void(const Json::Value&,Json::Value&)>;using ParamsDescribe=std::pair<std::string,VType>;ServiceDescribe();private:std::string _method_name;                 // 方法名称ServiceCallback _callback;                // 实际的业务回调函数std::vector<ParamsDescribe> _params_desc; // 参数字段格式描述VType _return_type;                       // 结果作为返回值类型的描述};///
//调用 建造者模式,便于服务生产class SDescribeFactory{public:private:std::string _method_name;                                  // 方法名称ServiceDescribe::ServiceCallback _callback;                // 实际的业务回调函数std::vector<ServiceDescribe::ParamsDescribe> _params_desc; // 参数字段格式描述VType _return_type;                                        // 结果作为返回值类型的描述};///class ServiceManager{public:using ptr=std::shared_ptr<ServiceManager>;//增void insert(const ServiceDescribe::ptr &desc){}//查//删private:std::mutex _mutex;std::unordered_map<std::string,ServiceDescribe::ptr> _services;};///class RpcRouter{public:using ptr = std::shared_ptr<RpcRouter>;RpcRouter() : _service_manager(std::make_shared<ServiceManager>()) {}private:ServiceManager::ptr _service_manager;};
}

ServiceDescribe

    class ServiceDescribe{public:using ptr=std::shared_ptr<ServiceDescribe>;using ServiceCallback=std::function<void(const Json::Value&,Json::Value&)>;using ParamsDescribe=std::pair<std::string,VType>;//构造 函数ServiceDescribe(std::string &&mname, std::vector<ParamsDescribe> &&desc,VType vtype, ServiceCallback &&handler) : _method_name(std::move(mname)), _callback(std::move(handler)),_params_desc(std::move(desc)), _return_type(vtype){}//通过 move && 减少了拷贝const std::string &method(){return _method_name;}//针对 请求中的参数 进行校验bool paramCheck(const Json::Value &params){// 对params进行参数校验---判断所描述的参数字段是否存在,类型是否一致//! eg. <"num1",int>for (auto &desc : _params_desc){if (params.isMember(desc.first) == false){ELOG("参数字段完整性校验失败!%s 字段缺失!", desc.first.c_str());return false;}if (check(desc.second, params[desc.first]) == false){ELOG("%s 参数类型校验失败!", desc.first.c_str());return false;}}return true;}bool call(const Json::Value &params, Json::Value &result){_callback(params, result);if (rtypeCheck(result) == false){ELOG("回调处理函数中的响应信息校验失败!");return false;}return true;}private:bool rtypeCheck(const Json::Value &val){return check(_return_type, val);}bool check(VType vtype, const Json::Value &val){switch (vtype){case VType::BOOL:return val.isBool();case VType::INTEGRAL:return val.isIntegral();case VType::NUMERIC:return val.isNumeric();case VType::STRING:return val.isString();case VType::ARRAY:return val.isArray();case VType::OBJECT:return val.isObject();}return false;}private:std::string _method_name;                 // 方法名称ServiceCallback _callback;                // 实际的业务回调函数std::vector<ParamsDescribe> _params_desc; // 参数字段格式描述VType _return_type;                       // 结果作为返回值类型的描述};

1.

SDescribeFactory

//调用 建造者模式,便于服务生产
//防止 数据 被修改,实现了 解耦合class SDescribeFactory {public:void setMethodName(const std::string &name) {_method_name = name;}void setReturnType(VType vtype) {_return_type = vtype;}void setParamsDesc(const std::string &pname, VType vtype) {_params_desc.push_back(ServiceDescribe::ParamsDescribe(pname, vtype));}void setCallback(const ServiceDescribe::ServiceCallback &cb) {_callback = cb;}ServiceDescribe::ptr build() {return std::make_shared<ServiceDescribe>(std::move(_method_name), std::move(_params_desc), _return_type, std::move(_callback));}private:std::string _method_name;ServiceDescribe::ServiceCallback _callback;  // 实际的业务回调函数std::vector<ServiceDescribe::ParamsDescribe> _params_desc; // 参数字段格式描述VType _return_type; //结果作为返回值类型的描述};

⭕ Builder模式

详见:设计模式 专栏,之后可能会从语雀 迁移同步到 CSDN

1. 动机

在软件系统中,有时候面临着“一个复杂对象”的创建工作

其通常由各个部分的子对象用一定的算法构成;

由于需求的变化,这个复杂对象的 各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。如何应对这种变化?

如何提供一种“封装机制”来隔离出 “复杂对象的各个部分” 的变化,从而保持系统中的“稳定构建算法”不 随着需求改变而改变?

2. 模式定义
  • 定义:将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。
  • 结构:未详细描述。

3. 要点总结
  • Builder模式主要用于“分步骤构建一个复杂的对象”。这其中 “分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。
  • 变化点在哪里,封装哪里 —— Builder模式主要在于 应对“复杂对象各个部分”的频繁需求变动。
  • 缺点:难以应对“分步骤构建算法”的需求变动。
  • 在Builder模式中,要注意不同语言中构造器内调用虚函数的差别(C++ vs C#)。
  • 与工厂模式相比:
    • 注重点不同:Builder模式更注重于方法的调用过程;工厂模式注重于创建产品,不关心方法调用的顺序。
    • 创建对象力度不同:建造者模式 可以创建复杂的产品,由各种复杂的部件组成;工厂模式创建出来的都是相同的实例对象。
4. 代码感受
// 抽象基类
class House {};// 抽象基类
class HouseBuilder 
{
public:House* GetResult(){return pHouse;}virtual ~HouseBuilder(){}protected:House* pHouse;virtual void BuildPart1() = 0;virtual void BuildPart2() = 0;virtual void BuildPart3() = 0;virtual void BuildPart4() = 0;virtual void BuildPart5() = 0;
};class StoneHouse: public House {};class StoneHouseBuilder: public HouseBuilder
{
protected:virtual void BuildPart1(){//pHouse->Part1 = ...;}virtual void BuildPart2(){}virtual void BuildPart3(){}virtual void BuildPart4(){}virtual void BuildPart5(){}
};class HouseDirector
{
public:HouseBuilder* pHouseBuilder;HouseDirector(HouseBuilder* pHouseBuilder){this->pHouseBuilder = pHouseBuilder;}House* Construct(){pHouseBuilder->BuildPart1();for (int i = 0; i < 4; i++){pHouseBuilder->BuildPart2();}bool flag=pHouseBuilder->BuildPart3();if(flag){pHouseBuilder->BuildPart4();}pHouseBuilder->BuildPart5();return pHouseBuilder->GetResult();}
};

ServiceManager

实现 对于<主题method,描述 desc> 的增 删 查 功能

class ServiceManager {//!<主题method,描述>public:using ptr = std::shared_ptr<ServiceManager>;void insert(const ServiceDescribe::ptr &desc)  {std::unique_lock<std::mutex> lock(_mutex);_services.insert(std::make_pair(desc->method(), desc));}ServiceDescribe::ptr select(const std::string &method_name) {std::unique_lock<std::mutex> lock(_mutex);auto it = _services.find(method_name);if (it == _services.end()) {return ServiceDescribe::ptr();}return it->second;}void remove(const std::string &method_name) {std::unique_lock<std::mutex> lock(_mutex);//加锁//自动释放锁_services.erase(method_name);}private:std::mutex _mutex;std::unordered_map<std::string, ServiceDescribe::ptr> _services;};

RpcRouter

    class RpcRouter {public:using ptr = std::shared_ptr<RpcRouter>;RpcRouter(): _service_manager(std::make_shared<ServiceManager>()){}//!!!!在Dispatcher前,进行Router检查void onRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &request){//1. 查询客户端请求的方法描述--判断当前服务端能否提供对应的服务auto service = _service_manager->select(request->method());if (service.get() == nullptr) {ELOG("%s 服务未找到!", request->method().c_str());return response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);}//2. 进行参数校验,确定能否提供服务if (service->paramCheck(request->params()) == false) {ELOG("%s 服务参数校验失败!", request->method().c_str());return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);}//3. 调用业务回调接口进行业务处理Json::Value result;//<int,33>bool ret = service->call(request->params(), result);if (ret == false) {ELOG("%s 服务参数校验失败!", request->method().c_str());return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR);//内部错误}//4. 处理完毕得到结果,组织响应,向客户端发送return response(conn, request, result, RCode::RCODE_OK);}//服务注册接口void registerMethod(const ServiceDescribe::ptr &service) {return _service_manager->insert(service);}private:void response(const BaseConnection::ptr &conn, const RpcRequest::ptr &req, const Json::Value &res, RCode rcode) {auto msg = MessageFactory::create<RpcResponse>();msg->SetId(req->GetId());msg->SetMType(bitrpc::MType::RSP_RPC);msg->setRCode(rcode);msg->setResult(res);conn->send(msg);}private:ServiceManager::ptr _service_manager;};

RpcRouter模块:一个枚举四个类

1. 枚举类:

  • 枚举出rpc请求参数的类型(布尔,整形,浮点型,字符串,数组,对象)

2. 服务描述类:

  • 业务回调函数 --- Add处理回调函数
  • 参数信息描述 --- pair<参数字段名称,参数字段类型> {<"num1", int>, <"num2", int>}
  • 返回值类型描述 --- int
  • 提供参数校验接口 --- 针对请求中的参数,判断是否包含有num1字段,其类型是否是整形
    • 处理逻辑:收到一个rpc请求后,取出方法名称,参数信息,
      • 通过方法名称Add,找到Add服务的描述对象,先进行参数校验,校验参数中是否具有num1字段,且类型是整形,
      • 判断都没问题则调用回调函数进行处理

3. 服务管理类:

  • 服务端会提供很多方法服务,需要进行良好的管理
    • std::hash_map<方法名称method,服务描述desc>
    • 通过这个hash_map 就可以很容易判断能否提供某个服务
    • 判断完 之后 ,再通过dispatcher 判断Callback

4. sum: 对外RpcRouter类:

  • 服务注册接口;
  • 提供给dispatcher模块的rpc请求处理回调函数( RpcRouter 检查后,再 Dispetcher 调度)

相关文章:

[实现Rpc] 服务端 | RpcRouter实现 | Builder模式

目录 项目服务端独用类的实现 1. RpcRouter类的实现 ServiceDescribe SDescribeFactory ⭕ Builder模式 1. 动机 2. 模式定义 3. 要点总结 4. 代码感受 ServiceManager RpcRouter 4. 代码感受 ServiceManager RpcRouter 前文我们就将 Rpc 通用类都实现完啦&#…...

红外人体传感器选型和电路解析

红外人体传感器选型和电路解析 背景&#xff1a;想要制作一套IoT系统&#xff0c;基于HA构建上层管理&#xff0c;蓝牙和蓝牙MESH构建无线网络&#xff0c;以及多种传感器和控制器作为底层&#xff0c;其中人体红外传感器作为一个重要的选项&#xff0c;需要考虑好。 红外人体传…...

rtthread的串口框架、485框架

一、串口接收超时中断的实现。 1. rtthread中定义的串口超时结构体 定义串口接收超时的结构体 CM_TMR0_TypeDef 为TM0的实例(实际有CM_TMR0_1 CM_TMR0_2 对应华大460的两个TMR0单元 ) channel 每个timer0有两个通道(TMR0_CHA、TMR0_CHB) clock 为FCG2_PERIPH_TMR0_1、FCG…...

Embedding模型

检索的方式有那些 关键字搜索&#xff1a;通过用户输入的关键字来查找文本数据。 语义搜索&#xff1a;它的目标是理解用户查询的真实意图&#xff0c;不仅考虑关键词的匹配&#xff0c;还考虑词汇之间的语义 &#xff08;文字&#xff0c;语音&#xff0c;语调...&#xff0…...

如何使用Spring Boot实现商品的管理系统

1. 项目初始化 1.1 使用 Spring Initializr 创建项目 访问 Spring Initializr,进行如下配置: Project:选择 Maven Project。Language:选择 Java。Spring Boot:选择合适的版本,如 3.1.x。Group:填写项目的组织名,例如 com.example。Artifact:填写项目名称,如 general…...

最新扣子(Coze)案例教程:全自动DeepSeek 写影评+批量生成 + 发布飞书,提效10 倍!手把手教学,完全免费教程

&#x1f468;‍&#x1f4bb;群里有同学是做影视赛道的博主&#xff0c;听说最近DeepSeek这么火&#xff0c;咨询能不能用DeepSeek写影评&#xff0c;并整理电影数据资料&#xff0c;自动发布到飞书文档&#xff0c;把每天的工作做成一个自动化的流程。 那今天斜杠君就为大家…...

Qt程序退出相关资源释放问题

目录 问题背景&#xff1a; aboutToQuit 代码举例 资源释放函数注意事项 closeEvent事件 代码举例 程序退出方式 quit() exit(int returnCode 0) close() 问题背景&#xff1a; 实际项目中程序退出前往往需要及进行一些资源释放、配置保存、线程中断等操作&#xff0c…...

Ubuntu 22.04安装K8S集群

以下是Ubuntu 22.04安装Kubernetes集群的步骤概要 一、设置主机名与hosts解析 # Master节点执行 sudo hostnamectl set-hostname "k8smaster" # Worker节点执行 sudo hostnamectl set-hostname "k8sworker1"# 所有节点的/etc/hosts中添加&#xff1a; ca…...

Kubernetes的Ingress 资源是什么?

在Kubernetes中&#xff0c;Ingress资源是一种用于管理集群外部对内部服务访问的API对象&#xff0c;主要用于将不同的外部请求路由到集群内的不同服务&#xff0c;以下是关于它的详细介绍&#xff1a; 定义与作用 Ingress资源定义了从集群外部到内部服务的HTTP和HTTPS路由规…...

Apifox 增强 AI 接口调试功能:自动合并 SSE 响应、展示DeepSeek思考过程

在现代的API接口调试中&#xff0c;效率和精确性对于开发者和测试人员来说至关重要。Apifox&#xff0c;作为一款功能强大的API管理和调试工具&#xff0c;近年来不断提升其用户体验和智能化功能。最近&#xff0c;Apifox 推出了增强版的AI接口调试功能&#xff0c;其中包括自动…...

MATLAB基础学习相关知识

MATLAB安装参考&#xff1a;抖音-记录美好生活 MATLAB基础知识学习参考&#xff1a;【1小时Matlab速成教程-哔哩哔哩】 https://b23.tv/CnvHtO3 第1部分&#xff1a;变量定义和基本运算 生成矩阵&#xff1a; % 生成矩阵% 直接法% ,表示行 ;表示列 a [1,2,3;4,5,6;7,8,9];%…...

DeepSeek赋能智慧文旅:新一代解决方案,重构文旅发展的底层逻辑

DeepSeek作为一款前沿的人工智能大模型&#xff0c;凭借其强大的多模态理解、知识推理和内容生成能力&#xff0c;正在重构文旅产业的发展逻辑&#xff0c;推动行业从传统的经验驱动向数据驱动、从人力密集型向智能协同型转变。 一、智能服务重构&#xff1a;打造全域感知的智…...

蓝桥与力扣刷题(蓝桥 交换瓶子)

题目&#xff1a;有 N 个瓶子&#xff0c;编号 1 ~ N&#xff0c;放在架子上。 比如有 5 个瓶子&#xff1a; 2 1 3 5 4 要求每次拿起 2 个瓶子&#xff0c;交换它们的位置。 经过若干次后&#xff0c;使得瓶子的序号为&#xff1a; 1 2 3 4 5 对于这么简单的情况&#x…...

腿足机器人之十一- 深度强化学习

腿足机器人之十一- 深度强化学习 机器人能力腿足机器人RL问题建模强化学习解决方案 强化学习算法库选择建议 深度学习技术已经在语音、图像、视频、文本等领域应用广泛&#xff0c;其和强化学习的结合使得基于深度学习的大模型能力更是上升一个台阶。因而用在腿足机器人的运动中…...

纠错检索增广生成论文

一、摘要 动机&#xff1a;RAG严重依赖于检索文档的相关性&#xff0c;如果检索出错&#xff0c;那么LLM的输出结果也会出现问题 解决方案&#xff1a;提出纠正性检索增强生成&#xff08;CRAG&#xff09;即设计一个轻量级的检索评估器&#xff0c;用来评估针对某个查询检索…...

多源 BFS 算法详解:从原理到实现,高效解决多源最短路问题

多源 BFS 是一种解决 边权为 1 的多源最短路问题 的高效算法。其核心思想是将所有源点视为一个“超级源点”&#xff0c;通过一次 BFS 遍历即可计算所有节点到最近源点的最短距离。以下从原理、实现和代码示例三个方面深入讲解&#xff1a; 目录 一、原理分析 1. 单源 BFS vs…...

Jenkins 构建 Unity 打包 .apk 同时生成 .aab

Jenkins 构建 Unity 打包 .apk 同时生成 .aab Android App Bundle简称 AAB&#xff0c;想了解更多关于 AAB 的知识&#xff0c;请看官网 https://developer.android.google.cn/guide/app-bundle/faq?hlzh-cn APK 打包部分在复用上一篇 Jenkins 构建 Unity打包APK 一、新建一…...

LTO优化详解

嵌入式开发过程中的LTO优化是什么意思&#xff1f;能够用来解决什么问题&#xff1f;它都优化了哪些&#xff1f;仅开启LTO真的可以优化SIZE的问题吗? 请分别回答我刚才提到的问题&#xff1f; 嗯&#xff0c;用户问关于嵌入式开发中的LTO优化&#xff0c;我需要详细解释这个概…...

嵌入式之条件编译

在C编程中&#xff0c;条件编译是一种在编译时根据特定条件选择性地包含或排除代码的技术。它通过预处理器指令来实现&#xff0c;允许程序员根据不同的编译环境、平台或配置来控制哪些代码被编译。条件编译在跨平台开发、调试、功能开关场景中非常有用。 1. 预处理器指令 条…...

清华大学第五弹:《DeepSeek与AI幻觉》

作者&#xff1a;清华大学新闻与传播学院新媒体研究中心、人工智能学院&#xff08;新媒沈阳团队&#xff09; 时间&#xff1a;2025年2月 完整版下载地址&#xff1a;夸克网盘分享 一、AI幻觉的定义与分类 定义 学术定义&#xff1a;模型生成与事实不符、逻辑断裂或脱离上下…...

理解构件的3种分类方法

对于Java程序员来说&#xff0c;理解“构件分类方法”是非常重要的&#xff0c;因为这直接关系到如何高效地管理和复用软件组件。以下是针对三种常见分类方法的具体解释&#xff1a; 构件的3种分类方法 1. 关键字分类法 (Keyword Classification Method) 关键字分类法是最直…...

分布式数据库解析

title: 分布式数据库解析 date: 2025/2/20 updated: 2025/2/20 author: cmdragon excerpt: 通过金融交易、社交平台、物联网等9大真实场景,结合Google Spanner跨洲事务、DynamoDB毫秒级扩展等38个生产级案例,揭示分布式数据库的核心原理与工程实践。内容涵盖CAP定理的动态…...

Zotero 快速参考文献导出(特定期刊引用)

目录 一、添加样式 每次投期刊时每种期刊的引用方式不一样&#xff0c;就很麻烦。发现zeotero添加期刊模板再导入很方便 一、添加样式 然后就能导出自己想要的期刊格式的引用了...

库的制作与原理(一)

1.库的概念 库是写好的&#xff0c;现成的可以复用的代码。本质上库是一种可执行的二进制形式&#xff0c;可以被操作系统载入内存执行。库有俩种&#xff1a;静态库 .a[Linux] .lib[windows] 动态库 .so[Linux] .dll[windows] 就是把.c文件变成.o文件&#xff0c;把…...

go 日志框架

内置log import ("log""os" )func main() {// 设置loglog.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)// 自定义日志前缀log.SetPrefix("[pprof]")log.Println("main ..")// 如果用format就用PrintF&#xff0c;而不是…...

JavaScript 最佳实践

我只选取了我还没完全贯彻的条目罗列如下. 1.函数命名 函数名由动词开头,如getName(); 2.布尔类型命名 若函数返回布尔值,则函数名以is/can等开头. 3.常量命名约定 常量名全大写并以下划线""连接. 4.变量类型透明化 定义变量时,应将其立即初使化为一个与其同类型…...

Rust配置笔记

1.Node.js下载配置 2.c环境配置 C我是用vs装的点击这个installer 点击修改 选择C环境就行,这个时候它就帮忙配置环境了 3.Rust下载配置 4.装napi-rs框架 npm install -g napi-rs/cliRust下载网站 下完之后直接打开 一开始下包会比较慢,多等等 下好之后跑项目前第一件事配置…...

大模型WebUI:Gradio全解12——LangChain原理及agents构建Gradio UI(1)

大模型WebUI:Gradio全解12——LangChain原理及agents构建Gradio UI(1) 前言本篇摘要12. LangChain原理及其agent构建Gradio UI12.1 LangChain介绍12.1.1 概念12.1.2 用途12.1.3 文档参考文献前言 本系列文章主要介绍WEB界面工具Gradio。Gradio是Hugging Face发布的简易WebU…...

具有整合各亚专科医学领域知识能力的AI智能体开发纲要(2025版)

整合各亚专科医学领域知识能力的AI代理的开发与研究 一、引言 1.1 研究背景 在科技飞速发展的当下,人工智能(AI)已成为推动各行业变革的关键力量,医疗领域也不例外。近年来,AI 在医疗行业的应用取得了显著进展,从医学影像诊断到疾病预测,从药物研发到个性化医疗,AI 技…...

机器学习在脑卒中预测中的应用:不平衡数据集处理方法详解

机器学习在脑卒中预测中的应用:不平衡数据集处理方法详解 目录 引言 脑卒中的全球影响机器学习在医疗预测中的挑战类别不平衡问题的核心痛点数据预处理与特征选择 数据来源与清洗缺失值处理方法类别特征编码特征选择技术处理类别不平衡的四大方法 SMOTE(合成少数类过采样技术…...