protobuf入门实践1

protobuf入门实践1

下载和安装

protobuf:https://github.com/google/protobuf
解压压缩包:unzip protobuf-master.zip
2、进入解压后的文件夹:cd protobuf-master
3、安装所需工具:sudo apt-get install autoconf automake libtool curl make g++ unzip
4、自动生成configure配置文件:./autogen.sh
5、配置环境:./configure
6、编译源代码(时间比较长):make

完成之后输入protoc,如下输出即安装成功
在这里插入图片描述

proto配置文件

syntax = "proto3"; //声明protobuf的版本package fixbug;   //声明了代码所在的包 (对于C++来说就是namespace)//定义登录请求消息类型   name   pwd
message LoginRequest{bytes name = 1;   //等于1表示这是第一个参数,一般string的存储定义为bytesbytes pwd = 2;
}//定义登录响应消息类型
message LoginResponse{int32 errcode = 1;bytes errmsg = 2;bool success = 3;
}

xxx.proto文件定义了protobuf的版本,更重要的是定义了用户后面需要序列和反序列化的自定义消息类型,这会当做后面的远程rpc调用的参数类型。
message是protobuf内置的抽象类message,用于定义远程rpc传输的各种消息类型,语法是:
message{数据类型 变量名 = index}, 数据类型既可以是内置的基本的数据类型也可以是其他message类型。
上述简单定义了一个登陆所需要的请求消息以及响应消息。

protobuf支持多种语言,可以将上述proto配置文件编译成所支持的任意语言,例如c++、java等等
下面通过protoc命令编译为c++版本
输入protoc xxx.proto --cpp_out=./, 表示在当前目录下生产proto配置文件所对应用户端可以使用的文件(C++源文件)如下:
在这里插入图片描述
如何使用这些源文件?

#include "test.pb.h"
#include <iostream>
#include <string>using namespace fixbug;int main(){    //封装login请求对象的数据LoginRequest req;req.set_name("zhang san");req.set_pwd("123456");//将LoginRequest对象序列化成字节数组(char*)std::string send_str;if(req.SerializeToString(&send_str)){std::cout<< send_str.c_str() << "\n";}//从send_str反序列化出一个login请求对象LoginRequest reqB;if(reqB.ParseFromString(send_str)){std::cout<<"name:"<<reqB.name()<<"\n"<<"pwd:"<<reqB.pwd()<<"\n";}return 0;
}

执行g++ main.cc test.pb.cc -lprotobuf && ./a.out
在这里插入图片描述
应该看起来还挺简单的,需要注意的是ResultCode变量的获取是,fixbug就是namespace fixbug, 然后每个消息类型对应在xxx.pb.cc文件中就是再fixbug命名空间下的一个类,消息类型里面定义的参数类型就是类里面的成员变量,并提供了这些成员变量的set_xxx(),xxx()方法来用于设置这些成员变量和获取该变量。是不是这样呢?看看生成的xxx.pb.h类吧:

namespace fixbug {
class GetFriendsListRequest;
class GetFriendsListRequestDefaultTypeInternal;
extern GetFriendsListRequestDefaultTypeInternal _GetFriendsListRequest_default_instance_;
class GetFriendsListResponse;
class GetFriendsListResponseDefaultTypeInternal;
extern GetFriendsListResponseDefaultTypeInternal _GetFriendsListResponse_default_instance_;
class LoginRequest;
class LoginRequestDefaultTypeInternal;
extern LoginRequestDefaultTypeInternal _LoginRequest_default_instance_;
class LoginResponse;
class LoginResponseDefaultTypeInternal;
extern LoginResponseDefaultTypeInternal _LoginResponse_default_instance_;
class ResultCode;
class ResultCodeDefaultTypeInternal;
extern ResultCodeDefaultTypeInternal _ResultCode_default_instance_;
class User;
class UserDefaultTypeInternal;
extern UserDefaultTypeInternal _User_default_instance_;
}  // namespace fixbug

可以很清楚的看到,的确是这样,定义的消息数据类型都是一个个类,那么看看具体的一个LoginRequest类:

class LoginRequest :public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:fixbug.LoginRequest) */ {public:LoginRequest();virtual ~LoginRequest();LoginRequest(const LoginRequest& from);LoginRequest(LoginRequest&& from) noexcept: LoginRequest() {*this = ::std::move(from);}...........// bytes name = 1;void clear_name();const std::string& name() const;void set_name(const std::string& value);void set_name(std::string&& value);void set_name(const char* value);void set_name(const void* value, size_t size);std::string* mutable_name();std::string* release_name();void set_allocated_name(std::string* name);private:const std::string& _internal_name() const;void _internal_set_name(const std::string& value);std::string* _internal_mutable_name();public:// bytes pwd = 2;void clear_pwd();const std::string& pwd() const;void set_pwd(const std::string& value);void set_pwd(std::string&& value);void set_pwd(const char* value);void set_pwd(const void* value, size_t size);std::string* mutable_pwd();std::string* release_pwd();void set_allocated_pwd(std::string* pwd);private:const std::string& _internal_pwd() const;void _internal_set_pwd(const std::string& value);std::string* _internal_mutable_pwd();private:class _Internal;::PROTOBUF_NAMESPACE_ID::internal::InternalMetadataWithArena _internal_metadata_;::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_; ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr pwd_;mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;friend struct ::TableStruct_test_2eproto;
.....
};

可以看到的确如我们所说。

再来修改一下proto文件,介绍一下列表的使用,因为在参数调用过程中,要么就是单个数据,要么就是该数据组成的列表,当然还有映射类型(有兴趣可以自行了解)

syntax = "proto3"; //声明protobuf的版本package fixbug;   //声明了代码所在的包 (对于C++来说就是namespace)message ResultCode{  //定义返回的错误码int32 errcode = 1;bytes errmsg = 2;
}//定义登录请求消息类型   name   pwd
message LoginRequest{bytes name = 1;   //等于1表示这是第一个参数,一般string的存储定义为bytesbytes pwd = 2;
}//定义登录响应消息类型
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;  //定义了一个列表数据类型
}

这里新增了三个消息类型,分别是User、GetFriendsListRequest、GetFriendsListResponse, 在GetFriendsListResponse消息类型中repeated 关键字是定义多个User,即一个User列表,这里需要注意的是为了避免代码重复,将错误码errcode和错误消息errmsg抽象成一个单独的消息类型。
老样子:protoc xxx.proto --cpp_out=./

#include "test.pb.h"
#include <iostream>
#include <string>using namespace fixbug;int main(){// LoginResponse rsp;// ResultCode* res = rsp.mutable_result();// rsp.set_success(0);// res->set_errcode(1);// res->set_errmsg("login failed");GetFriendsListResponse list; //列表操作ResultCode* rc = list.mutable_result();rc->set_errcode(0);rc->set_errmsg("");//添加用户User* u1 = list.add_friend_list();u1->set_name("zs");u1->set_age(21);u1->set_sex(User::MAN);User* u2 = list.add_friend_list();u2->set_name("ls");u2->set_age(21);u2->set_sex(User::MAN);std::cout<<"list size = "<<list.friend_list_size()<<"\n";for(int i = 0; i<list.friend_list_size(); i++){User u = list.friend_list(i);std::cout<<"name : "<< u.name()<<" ";std::cout<<"age : "<<u.age()<<" ";std::cout<<"sex : "<<u.sex()<<"\n";}return 0;
}

错误码和错误消息由于也封装成了一个消息,这里获取是通过::mutable_result()方法返回一个该变量的指针,对该指针的修改就行对原ResultCode对象类型的赋值操作。后面就是列表的操作,通过add_friend_list()方法返回一个需要新添加的User,friend_list_size()用于获取列表的长度,friend_list()用于得到列表中某个索引的User对象。

执行结果:
list size = 2
name : zs age : 21 sex : 0
name : ls age : 21 sex : 0

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

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

相关文章

PostgreSQL数据库动态共享内存管理器——Dynamic shared memory areas

dsm.c提供的功能允许创建后端进程间共享的共享内存段。DSA利用多个DSM段提供共享内存heap&#xff1b;DSA可以利用已经存在的共享内存&#xff08;DSM段&#xff09;也可以创建额外的DSM段。和系统heap使用指针不同的是&#xff0c;DSA提供伪指针&#xff0c;可以转换为backend…

python与深度学习(六):CNN和手写数字识别二

目录 1. 说明2. 手写数字识别的CNN模型测试2.1 导入相关库2.2 加载数据和模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章训练的模型进行测试…

工具推荐:Linux Busybox

文章首发地址 BusyBox是一个开源的、轻量级的、可嵌入式的、多个Unix工具的集合。BusyBox提供了各种Unix工具的实现&#xff0c;包括文件处理工具、网络工具、shell工具、系统管理工具、进程管理工具等等。它被设计为一个小巧、高效、可靠、易于维护的工具&#xff0c;适用于嵌…

微服务——服务异步通讯RabbitMQ

前置文章 消息队列——RabbitMQ基本概念容器化部署和简单工作模式程序_北岭山脚鼠鼠的博客-CSDN博客 消息队列——rabbitmq的不同工作模式_北岭山脚鼠鼠的博客-CSDN博客 消息队列——spring和springboot整合rabbitmq_北岭山脚鼠鼠的博客-CSDN博客 目录 Work queues 工作队列…

设计模式 - 工厂模式

一、 简单工厂&#xff08;Simple Factory Pattern&#xff09; 1、概念 一个工厂对象决定创建出哪一种产品类的实力&#xff0c;但不属于GOF23种设计模式。 简单工厂适用于工厂类负责创建的对象较少的场景&#xff0c;且客户端只需要传入工厂类的参数&#xff0c;对于如何创…

Andrew算法求凸包模板

前置知识 向量的叉乘: 设 a ⃗ ( x a , y a , z a ) , b ⃗ ( x b , y b , z b ) \vec a(x_a,y_a,z_a), \vec b(x_b, y_b,z_b) a (xa​,ya​,za​),b (xb​,yb​,zb​), 令 a ⃗ \vec a a 和 b ⃗ \vec b b 的叉乘为 c ⃗ \vec c c , 有: c ⃗ ∣ i j k x a y a z a x b y…

【深度学习】GPT-3

2020年5月&#xff0c;OpenAI在长达72页的论文《https://arxiv.org/pdf/2005.14165Language Models are Few-Shot Learners》中发布了GPT-3&#xff0c;共有1750亿参数量&#xff0c;需要700G的硬盘存储&#xff0c;(GPT-2有15亿个参数)&#xff0c;它比GPT-2有了极大的改进。根…

钉钉返回:访问ip不在白名单之中,请参考FAQ

新版钉钉 在开发管理-服务器出口IP-配置返回错误信息返回给你的requestIp

k8s部署新版elasticsearch+kibana并配置快照备份

版本:es 7.17.6 kibana 7.17.6 k8s:1.19.16 一、介绍 Elasticsearch和Kibana是一对强大的开源工具&#xff0c;通常一起使用以构建实时数据分析和可视化解决方案。 Elasticsearch: Elasticsearch是一个分布式、高性能的实时搜索和分析引擎。它构建在开源搜索引擎库Lucene之上…

【C++】开源:Redis数据库配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Redis数据库配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c…

边缘计算对现代交通的重要作用

边缘计算之所以重要&#xff0c;是在于即使在5G真正商用之时&#xff0c;可以实现超大带宽&#xff08;eMBB&#xff09;的应用场景&#xff0c;但庞大数据量的涌现也就意味着需要在云和端传输过程中找到一个承接点&#xff0c;对数据进行预处理再选择是否上云。 边缘计算应用演…

【Python入门【推导式创建序列、字典推导式、集合推导式】(九)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…

SkyWalking链路追踪-技术文档首页

SkyWalking 文档中文版&#xff08;社区提供&#xff09; (skyapm.github.io)https://skyapm.github.io/document-cn-translation-of-skywalking/ SkyWalking-基本概念 SkyWalking链路追踪是一个用于分布式系统的性能监控工具&#xff0c;它帮助开发人员了解系统中各组件之间…

工程安全监测无线振弦采集仪在建筑物的应用分析

工程安全监测无线振弦采集仪在建筑物的应用分析 工程安全监测无线振弦采集仪是一种在建筑物中应用的重要设备。它通过无线采集建筑物内部的振动信息&#xff0c;对建筑物的安全性进行监测和评估&#xff0c;为建筑物的施工和使用提供了可靠的技术支持。本文将详细介绍工程安全…

ElasticSearch基础篇-安装与基本操作

ElasticSearch基础篇 安装 官网 下载地址 下载完成后对文件进行解压&#xff0c;项目结构如下 进入bin目录点击elasticsearch.bat启动服务 9300 端口为 Elasticsearch 集群间组件的通信端口&#xff0c; 9200 端口为浏览器访问的 http协议 RESTful 端口 打开浏览器&#…

力扣热门100题之矩阵置0【中等】

题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 示例 2&#xff…

C++ - list介绍 和 list的模拟实现

list介绍 list 是一个支持在常数范围内&#xff0c;任意位置进行插入删除的序列式容器&#xff0c;且这个容器可以前后双向迭代。我们可以把 list 理解为 双向循环链表的结构。 于其他结构的容器相比&#xff0c;list在 任意位置进行插入和函数的效率要高很多&#xff1b;而li…

SWF格式视频怎么转换成AVI格式?简单的转换方法分享

当你想要在不同的设备上播放视频时&#xff0c;将SWF格式视频转换成AVI格式是非常有用的。因为SWF格式通常只能在特定的软件或网页上播放&#xff0c;而AVI格式则可以在更广泛的设备上播放&#xff0c;包括智能手机&#xff0c;平板电脑和电视机等。那么我们怎么将SWF转换成AVI…

AI学习笔记四:yolov5训练自己的数据集

若该文为原创文章&#xff0c;转载请注明原文出处。 一般情况下&#xff0c;大部分人的电脑都是没有cpu的&#xff0c;cpu也是可以训练的&#xff0c;但花费的时间太长&#xff0c;实际200张图片&#xff0c;使用CPU训练300轮花了3天&#xff0c;本章记录使用云服务器来训练自…

SkyWalking链路追踪-搭建-spring-boot-cloud-单机环境 之《10 分钟快速搭建 SkyWalking 服务》

首先了解一下单机环境 第一步&#xff0c;搭建一个 Elasticsearch 服务。第二步&#xff0c;下载 SkyWalking 软件包。第三步&#xff0c;搭建一个 SkyWalking OAP 服务。第四步&#xff0c;启动一个 Spring Boot 应用&#xff0c;并配置 SkyWalking Agent。第五步&#xff0c;…