protobuf入门实践1

news2024/11/24 6:23:55

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的存储定义为bytes
    bytes 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的存储定义为bytes
    bytes 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.coloradmin.cn/o/795221.html

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

相关文章

企业计算机服务器数据库中了360后缀勒索病毒怎么解决,数据恢复

近日&#xff0c;一家中型企业的服务器数据库遭到了一起严重的网络安全事件&#xff0c;导致企业的运营暂时陷入混乱。据了解&#xff0c;该企业的技术人员在服务器数据库中发现了一种名为“360后缀”勒索病毒&#xff0c;该勒索病毒通过对企业重要文件进行加密&#xff0c;数据…

node.js 爬虫图片下载

主程序文件 app.js 运行主程序前需要先安装使用到的模块&#xff1a; npm install superagent --save axios要安装指定版,安装最新版会报错&#xff1a;npm install axios0.19.2 --save const {default: axios} require(axios); const fs require(fs); const superagent r…

[每日习题]位运算——二进制插入 求最大连续bit数——牛客习题

hello&#xff0c;大家好这里是bang___bang_,今天记录2道关于位运算的牛客习题&#xff0c;二进制插入和求最大连续bit数&#xff0c;题目简单不难。 目录 1️⃣二进制插入 2️⃣求最大连续bit数 1️⃣二进制插入 二进制插入__牛客网 (nowcoder.com) 描述&#xff1a; 给定…

umi 创建的项目中,如何配置多个环境变量

创建env.js 在config.js中配置 在页面中使用 env.js和config.js的目录顺序 package.json中的配置

CountDownLatch和CyclicBarrier学习

CountDownLatch和CyclicBarrier都有一个计数器 CountDownLatch countDownLatch new CountDownLatch(4); CyclicBarrier cyclicBarrier new CyclicBarrier(4) CountDownLatch 是在 countDownLatch.countDown()执行后 4-1 等到4减到0后&#xff0c;就可以继续执行程序&#x…

QT控件通过qss设置子控件的对齐方式、大小自适应等

一些复杂控件&#xff0c;是有子控件的&#xff0c;每个子控件&#xff0c;都可以通过qss的双冒号选择器来选中&#xff0c;进行独特的样式定义。很多控件都有子控件&#xff0c;太多了&#xff0c;后面单独写一篇文章来介绍各个控件的子控件。这里就随便来几个例子 例如下拉列…

【AI换脸】roop在Kaggle上的使用样例

【AI换脸】roop在Kaggle上的使用样例 roop-kaggle前言换脸效果样例 GIF项目描述 roop-kaggle 【AI换脸】roop在Kaggle上的使用样例只需一张脸的图片&#xff0c;即可完成视频内的换脸点我进入Kaggle Notebook样例 前言 因为roop项目的Python环境依赖等问题的处理对于部分朋友…

环境监测系统网关,让景区变成智能化

景区环境监测系统采用先进的物联网网关&#xff0c;实现对各监测单元数据的采集、存储、传输和管理&#xff0c;主要对景点的气象要素、空气质量、水文变化、地质信息、雷电危害等进行监测&#xff0c;是一个集气象预警、在线监控等多种功能于一体的现代化综合系统。 系统介绍…

基于vue+uniapp微信小程序公司企业后勤服务(设备)系统

本系统分为用户和管理员两个角色&#xff0c;其中用户可以注册登陆系统&#xff0c;查看公司公告&#xff0c;查看设备&#xff0c;设备入库&#xff0c;查看通讯录&#xff0c;会议室预约&#xff0c;申请出入&#xff0c;申请请假等功能。管理员可以对员工信息&#xff0c;会…

【Linux】Centos的一些快捷操作

Centos的一些快捷操作 一个窗口多个终端GVIM 一个窗口多个文件 一个窗口多个终端 GVIM 一个窗口多个文件

2023十大最牛编程语言排行榜以及各语言的优缺点

文章目录 ⭐️ 2023年7月十大编程语言排行榜⭐️ 十大值得学习编程语言概要&#x1f31f; Python&#x1f31f; C/C&#x1f31f; Java&#x1f31f; C#&#x1f31f; JavaScript&#x1f31f; Swift&#x1f31f; Ruby&#x1f31f; GO&#xff08;Golang&#xff09;&#x1…

FreeRTOS函数的命名规则

在学习FreeRTOS的时候&#xff0c;经常遇到函数名前有“x”或“v"&#xff0c;实际上这代表了函数返回值的类型&#xff1a; &#xff08;参考了FreeRTOS系统中函数名和变量名的含义_vportenablevfp_Tinus Chen的博客-CSDN博客&#xff09;

Redis 命令介绍

文章目录 Redis字符串操作命令哈希操作命令列表操作命令set集合sorted set 有序集合通用命令 在Java中操作Redis&#x1f350; ❤️ &#x1f6a9;4.1 Redis的Java客户端 &#x1f350;4.2 Spring Data Redis使用方式 ✏️环境搭建步骤1). 导入Spring Data Redis的maven坐标2).…

xshell连接报错Socket error Event: 32 Error: 10053.

查看ssh服务端的日志 cat /var/log/auth.log |less 查看 ll /etc/ssh/ 发现以下文件的大小为0 /etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_rsa_key解决方案 生成rsa_key # ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key生成ecdsa_key # ssh-keygen -t ecdsa -f /et…

Python 集合 remove()函数使用详解,删除集合中的元素,删除多个元素

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 remove函数使用详解 1、删除多个元素2、删除不存在的元素会报错3、删除的元素可以…

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

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

C++ - stack 和 queue 模拟实现 -认识 deque 容器

stack模拟实现 用模版实现 链式栈 和 顺序栈 对于stack 的实现&#xff0c;有两种方式&#xff0c;一种是连续空间存储的顺序栈&#xff0c;一种是不连续空间存储的链式栈&#xff0c;在C当中如果要使用两种不同的栈的话&#xff0c;实现方式是不一样的&#xff0c;他们的底层逻…

新型双功能整合剂2374782-03-1,NOTA-FAPI-04,具有良好的配位和整合能力

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ NOTA-FAPI-04&#xff0c;大环化合物-FAPI-04 PART1----产品结构式 PART2----产品规格 1.CAS号&#xff1a;2374782-03-1 2.分子式&#xff1a;C36H47F2N9O8 3.分子量&#xff1a;771.8238 4.沸点 1061.865.0 C(Predicted)…

Unity自定义后处理——Tonemapping色调映射

大家好&#xff0c;我是阿赵。   继续介绍屏幕后处理&#xff0c;这一期介绍一下Tonemapping色调映射 一、Tone Mapping的介绍 Tone Mapping色调映射&#xff0c;是一种颜色的映射关系处理&#xff0c;简单一点说&#xff0c;一般是从原始色调&#xff08;通常是高动态范围&…

Langchain 集成 Milvus

Langchain 集成 Milvus 1. 安装 Docker2. 部署 Milvus3.4. Langchain 集成 Milvus 1. 安装 Docker refer: https://docs.docker.com/engine/install/centos/ Milvus 会以容器方式启动&#xff0c;所以先安装 Docker。(本示例使用的是 Alma Linux 9.2) 卸载旧版本&#xff0c…