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

protobuf入门实践2

如何在proto中定义一个rpc服务?

syntax = "proto3"; //声明protobuf的版本package fixbug;   //声明了代码所在的包 (对于C++来说就是namespace)//下面的选项,表示生成service服务类和rpc方法描述, 默认是不生成的
option cc_generic_services = true;message ResultCode{  //定义返回的错误码int32 errcode = 1;bytes errmsg = 2;
}//常用的数据类型: 数据、列表、映射表//定义登录请求消息类型   name   pwd
message LoginRequest{bytes name = 1;   //等于1表示这是第一个参数,一般string的存储定义为bytesbytes pwd = 2;// map<int32,string> test = 3; //映射表类型
}//定义登录响应消息类型
message LoginResponse{ResultCode result = 1;bool success = 3;
}message GetFriendsListRequest{uint32 user_id = 1;
}message User{bytes name = 1;uint32 age = 2;enum Sex{MAN = 0;WOMAN = 1;}Sex sex = 3;
}message GetFriendsListResponse{ResultCode result = 1;repeated User friend_list = 2;  //定义了一个列表数据类型
}//在protobuf里面怎么定义描述rpc方法的类型---service
service UserService{rpc Login(LoginRequest) returns(LoginResponse);rpc GetFriendsList(GetFriendsListRequest) returns(GetFriendsListResponse); 
}

关键字service用于定义rpc服务,例如Userservice有两个rpc服务,分别是Login和GetFriendsList, 返回值分别就是上述定义的消息类型。
老样子,先执行protoc xxx.proto --cpp_out=./ 生成对应的xxx.pb.cc 和 xxx.pb.h文件。
需要注意的是选项option cc_generic_services = true;得加上,默认是不生成的。
这边来分析xxx.pb.h文件,简单探究一下rpc调用过程:

//!!!!xxx.pb.h
class UserService : public ::PROTOBUF_NAMESPACE_ID::Service {protected:// This class should be treated as an abstract interface.inline UserService() {};public:virtual ~UserService();typedef UserService_Stub Stub;static const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* descriptor();virtual void Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::LoginRequest* request,::fixbug::LoginResponse* response,::google::protobuf::Closure* done);virtual void GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::GetFriendsListRequest* request,::fixbug::GetFriendsListResponse* response,::google::protobuf::Closure* done);// implements Service ----------------------------------------------const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* GetDescriptor();void CallMethod(const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method,::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::PROTOBUF_NAMESPACE_ID::Message* request,::PROTOBUF_NAMESPACE_ID::Message* response,::google::protobuf::Closure* done);const ::PROTOBUF_NAMESPACE_ID::Message& GetRequestPrototype(const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method) const;const ::PROTOBUF_NAMESPACE_ID::Message& GetResponsePrototype(const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method) const;private:GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UserService);
};
//!!!!xxx.pb.cc
void UserService::Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::LoginRequest*,::fixbug::LoginResponse*,::google::protobuf::Closure* done) {controller->SetFailed("Method Login() not implemented.");done->Run();
}void UserService::GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::GetFriendsListRequest*,::fixbug::GetFriendsListResponse*,::google::protobuf::Closure* done) {controller->SetFailed("Method GetFriendsList() not implemented.");done->Run();
}

可以看到一个UserService这个类,这个和message关键字有异曲同工之妙,都是对应的一个类,只不过继承的基类是有所不同的, message消息类型继承于抽象类message, service服务类型继承于抽象类service。此外可以发现在类中实现了在proto文件中定义的两个rpc方法Login和GetFriendsList, 其中两个参数是很熟悉的,request和response,也即这个rpc方法的需要用到的调用参数,类型message基类指针,表示可以接受任意消息类型。
由此可知UserService类是一个服务提供者(Callee)

再来看另一个类

//!!!!xxx.pb.h
class UserService_Stub : public UserService {public:UserService_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel);UserService_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel,::PROTOBUF_NAMESPACE_ID::Service::ChannelOwnership ownership);~UserService_Stub();inline ::PROTOBUF_NAMESPACE_ID::RpcChannel* channel() { return channel_; }// implements UserService ------------------------------------------void Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::LoginRequest* request,::fixbug::LoginResponse* response,::google::protobuf::Closure* done);void GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::GetFriendsListRequest* request,::fixbug::GetFriendsListResponse* response,::google::protobuf::Closure* done);private:::PROTOBUF_NAMESPACE_ID::RpcChannel* channel_;bool owns_channel_;GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UserService_Stub);//!!!!xxx.pb.cc
void UserService_Stub::Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::LoginRequest* request,::fixbug::LoginResponse* response,::google::protobuf::Closure* done) {channel_->CallMethod(descriptor()->method(0),controller, request, response, done);
}
void UserService_Stub::GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::GetFriendsListRequest* request,::fixbug::GetFriendsListResponse* response,::google::protobuf::Closure* done) {channel_->CallMethod(descriptor()->method(1),controller, request, response, done);
}

可以看见这个类没有无参构造,有几个RpcChannel*参数传递的构造方法,,不妨看看RpcChannel类:

class PROTOBUF_EXPORT RpcChannel {public:inline RpcChannel() {}virtual ~RpcChannel();// Call the given method of the remote service.  The signature of this// procedure looks the same as Service::CallMethod(), but the requirements// are less strict in one important way:  the request and response objects// need not be of any specific class as long as their descriptors are// method->input_type() and method->output_type().virtual void CallMethod(const MethodDescriptor* method,RpcController* controller, const Message* request,Message* response, Closure* done) = 0;private:GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
};

很显然,这是个抽象基类,需要用户自己实现派生类重写基类的CallMethod方法
在之后login和GetFriendsList两个方法基本调用方式一样,都是通过_channel调用CallMethod方法执行对应rpc调用,那么可知UserService_Stub是服务消费者(Caller)

如何发布一个本地rpc服务?

#include <iostream>
#include <string>
#include "user.pb.h"
class UserService : public fixbug::UserServiceRpc    //使用rpc服务发布端(rpc服务提供者)
{
public:bool Login(std::string name, std::string pwd){std::cout<<"doing local service : Login" << std::endl;std::cout<< "name:" << name << "pwd :" << pwd << std::endl;}    /*** 重写基类UserServiceRpc的虚函数 下面这些方法都是框架直接调用的* caller   ===> Login(LoginRequest)  ==> transmit ==>  callee* callee   ===> Login(LoginRequest) ===> 调用下述的Login方法* */void Login(::google::protobuf::RpcController* controller,const ::fixbug::LoginRequest* request,::fixbug::LoginResponse* response,::google::protobuf::Closure* done){//框架给业务上报了请求参数LoginRequest 应用获取相应数据做本地业务std::string name = request->name();std::string pwd = request->pwd();//本地业务bool res = Login(name, pwd);//把响应写入 包括错误码、错误消息、返回值response->set_success(0);fixbug::ResultCode* rc = response->mutable_result();rc->set_errcode(0);rc->set_errmsg("");//执行回调操作   执行响应对象数据的序列化和网络发送(由框架来完成)done->Run();}
};

继承对应的UserServiceRpc服务提供者,重写其基类方法即可。
上面只是发布过程,具体rpc调用待续。。。

相关文章:

protobuf入门实践2

如何在proto中定义一个rpc服务? syntax "proto3"; //声明protobuf的版本package fixbug; //声明了代码所在的包 &#xff08;对于C来说就是namespace)//下面的选项&#xff0c;表示生成service服务类和rpc方法描述&#xff0c; 默认是不生成的 option cc_generi…...

adb shell使用总结

文章目录 日志记录系统概览adb 使用方式 adb命令日志过滤按照告警等级进行过滤按照tag进行过滤根据告警等级和tag进行联合过滤屏蔽系统和其他App干扰&#xff0c;仅仅关注App自身日志 查看“当前页面”Activity文件传输截屏和录屏安装、卸载App启动activity其他 日志记录系统概…...

UG NX二次开发(C++)-Tag的含义、Tag类型与其他的转换

文章目录 1、前言2、Tag号的含义3、tag_t转换为int3、TaggedObject与Tag转换3.1 TaggedObject定义3.2 TaggedObject获取Tag3.3 根据Tag获取TaggedObject4.Tag与double类型的转换1、前言 在UG NX中,每个对象对应一个tag号,C++中,其类型是tag_t,一般是5位或者6位的int数字,…...

Informer 论文学习笔记

论文&#xff1a;《Informer: Beyond Efficient Transformer for Long Sequence Time-Series Forecasting》 代码&#xff1a;https://github.com/zhouhaoyi/Informer2020 地址&#xff1a;https://arxiv.org/abs/2012.07436v3 特点&#xff1a; 实现时间与空间复杂度为 O ( …...

c语言位段知识详解

本篇文章带来位段相关知识详细讲解&#xff01; 如果您觉得文章不错&#xff0c;期待你的一键三连哦&#xff0c;你的鼓励是我创作的动力之源&#xff0c;让我们一起加油&#xff0c;一起奔跑&#xff0c;让我们顶峰相见&#xff01;&#xff01;&#xff01; 目录 一.什么是…...

FFmpeg aresample_swr_opts的解析

ffmpeg option的解析 aresample_swr_opts是AVFilterGraph中的option。 static const AVOption filtergraph_options[] {{ "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS,{ .i64 AVFILTER_THREAD_SLICE }, 0, INT_MA…...

CAN学习笔记3:STM32 CAN控制器介绍

STM32 CAN控制器 1 概述 STM32 CAN控制器&#xff08;bxCAN&#xff09;&#xff0c;支持CAN 2.0A 和 CAN 2.0B Active版本协议。CAN 2.0A 只能处理标准数据帧且扩展帧的内容会识别错误&#xff0c;而CAN 2.0B Active 可以处理标准数据帧和扩展数据帧。 2 bxCAN 特性 波特率…...

软工导论知识框架(二)结构化的需求分析

本章节涉及很多重要图表的制作&#xff0c;如ER图、数据流图、状态转换图、数据字典的书写等&#xff0c;对初学者来说比较生僻&#xff0c;本贴只介绍基础的轮廓&#xff0c;后面会有单独的帖子详解各图表如何绘制。 一.结构化的软件开发方法&#xff1a;结构化的分析、设计、…...

[SQL挖掘机] - 算术函数 - abs

介绍: 当谈到 SQL 中的 abs 函数时&#xff0c;它是一个用于计算数值的绝对值的函数。“abs” 代表 “absolute”&#xff08;绝对&#xff09;&#xff0c;因此 abs 函数的作用是返回一个给定数值的非负值&#xff08;即该数值的绝对值&#xff09;。 abs 函数接受一个参数&a…...

vue拼接html点击事件不生效

vue使用ts&#xff0c;拼接html&#xff0c;点击事件不生效或者报 is not defined 点击事件要用onclick 不是click let data{name:测,id:123} let conHtml <div> "名称&#xff1a;" data.name "<br>" <p class"cursor blue&quo…...

【Spring】Spring之依赖注入源码解析

1 Spring注入方式 1.1 手动注入 xml中定义Bean&#xff0c;程序员手动给某个属性赋值。 set方式注入 <bean name"userService" class"com.firechou.service.UserService"><property name"orderService" ref"orderService"…...

【微软知识】微软相关技术知识分享

微软技术领域 一、微软操作系统&#xff1a; 微软的操作系统主要是 Windows 系列&#xff0c;包括 Windows 10、Windows Server 等。了解 Windows 操作系统的基本使用、配置和故障排除是非常重要的。微软操作系统&#xff08;Microsoft System&#xff09;是美国微软开发的Wi…...

12.python设计模式【观察者模式】

内容&#xff1a;定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变的时候&#xff0c;所有依赖于它的对象得到通知并被自动更新。观者者模式又称为“发布-订阅”模式。比如天气预报&#xff0c;气象局分发气象数据。 角色&#xff1a; 抽象主题&#xf…...

重生之我要学C++第五天

这篇文章主要内容是构造函数的初始化列表以及运算符重载在顺序表中的简单应用&#xff0c;运算符重载实现自定义类型的流插入流提取。希望对大家有所帮助&#xff0c;点赞收藏评论&#xff0c;支持一下吧&#xff01; 目录 构造函数进阶理解 1.内置类型成员在参数列表中的定义 …...

复习之linux高级存储管理

一、lvm----逻辑卷管理 1.lvm定义 LVM是 Logical Volume Manager&#xff08;逻辑卷管理&#xff09;的简写&#xff0c;它是Linux环境下对磁盘分区进行管理的一种机制。 逻辑卷管理器(LogicalVolumeManager)本质上是一个虚拟设备驱动&#xff0c;是在内核中块设备和物理设备…...

HuggingGPT Solving AI Tasks with ChatGPT and its Friends in Hugging Face

总述 HuggingGPT 让LLM发挥向路由器一样的作用&#xff0c;让LLM来选择调用那个专业的模型来执行任务。HuggingGPT搭建LLM和专业AI模型的桥梁。Language is a generic interface for LLMs to connect AI models 四个阶段 Task Planning&#xff1a; 将复杂的任务分解。但是这里…...

java工程重写jar包中class类覆盖问题

结论&#xff1a;直接在程序中复写jar中的类即可 原因&#xff1a;一般我java工程是运行在tomcat容器中&#xff0c;tomcat容易在加载我们工程类和jar包是的优先级为&#xff1a; 我们工程的class 先于 我们工程lib下的jar 重复的类只加载一次&#xff0c;加载我们复写后的类后…...

Mybatis基于注解与XML开发

文章目录 1 关于SpringBoot2 关于MyBatis2.1 MyBatis概述2.2 MyBatis核心思想2.3 MyBatis使用流程3 MyBatis配置SQL方式3.1 基于注解方式3.1.1 说明3.1.2 使用流程3.1.3 常用注解 3.2 基于XML方式3.2.1 相比注解优势3.2.2 使用流程3.2.3 常用标签 1 关于SpringBoot SpringBoot…...

数字化转型导师坚鹏:数字化时代扩大内需的8大具体建议

在日新月异的数字化时代、复杂多变的国际化环境下&#xff0c;扩大内需成为推动经济发展的国家战略&#xff0c;如何真正地扩大内需&#xff1f;结合本人15年的管理咨询经验及目前实际情况的深入研究&#xff0c;提出以下8大具体建议&#xff1a; 1、制定国民收入倍增计划。结…...

M1/M2 通过VM Fusion安装Win11 ARM,解决联网和文件传输

前言 最近新入了Macmini M2&#xff0c;但是以前的老电脑的虚拟机运行不起来了。&#x1f605;&#xff0c;实际上用过K8S的时候&#xff0c;会发现部分镜像也跑不起来&#xff0c;X86的架构和ARM实际上还是有很多隐形兼容问题。所以只能重新安装ARM Win11&#xff0c;幸好微软…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

算术操作符与类型转换:从基础到精通

目录 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符&#xff1a;、-、*、/、% 赋值操作符&#xff1a;和复合赋值 单⽬操作符&#xff1a;、--、、- 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...