protobuf学习总结

protobuf概念

protobuf 是一种平台无关、语言无关,可扩展的序列化数据格式,相比较与JSON和xml,具有高效性和灵活性。

定义Message

proto文件的定义

Message被定义为一个.proto文件

本文参考官方文档设计的Message如下:

// An highlighted block
syntax = "proto2";

package tutorial;

message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;

    enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }
    message PhoneNumber {
        required string number = 1;
        optional PhoneType type = 2 [default = HOME];
    }
    repeated PhoneNumber phones = 4;
    
}

message AddressBook {
    repeated Person people = 1;
}

首先,需要在声明使用的是proto协议的版本,package会被编译生成C++中的namespace;
譬如,package tutorial 会被编译生成namespace tutorial{};
每个Message 会被编译生成每个类,譬如message Person会被编译生成class Person;

Message 数字域与规则

由Message定义知,每个Message中均匀一些数字域,该数字域是唯一的;
不同的数字定义了mesage二进制编码格式的一个域;

10000—19999是系统保留的数字,不能用来定义类型

required:该消息域使用需要注意,如果在一个proto文件中将某个域定义为required,则其他使用者如果想改变该域,会导致错误;每个Message必须定义一个required

optional:如果optional域的变量为被设置,则Message在被解析时,会议默认值代替;每个Message可以定义或者不定义该域

repeated:该域能被重复0次或者多次,每次的值均会被保存

protobuf编码规则

整数编码规则

// An highlighted block
syntax = "proto2";
package Test_econd;

message Test1 {
    optional int32 a = 1;
    // optional string str = 2;
}

如上定义一个Message,利用protoc工具对其进行编译
编译命令为:
protoc -I=./pb --cpp_out=./pb ./pb/test.proto
-I 为包含proto的源文件路径,–cpp_out为编译生成的.h和.cc 所在的文件路径, 后面跟所要编译的proto文件

本文在实验时设置a=300;其序列化结果如下:

// An highlighted block
0000: 08ac 020a 

其序列化过程如下:

  1. 对于a=300;其数字域为1,因此1<<3,左移三位
  2. 其类型为int32, 因此用type=000表示
  3. 1<<3 | type =01000 = 08
  4. 300的二进制表示为100101100
  5. 在protobuf编码协议中,以整数的从低位开始数起,7位为一组,并增加一个最高有效位MSB,然后将组顺序想调,最高有效位为1表示改数字字节表示结束,为0表示这属于一个整数字节表示的一部份;
  6. 对于300的10 0101100,调转两组变为 0101100 10,由于0101100变为300的最高字节组,因此在其最高位加1变为1010 1100也即 ac,对于10,则补0变为00000010也即02,因此300编码的结果为08ac 02
  7. 至于最后的0a, 则是换行符的ASCII码值,pb序列化会在字节末尾加个换行符

string编码规则

借用官网的例子,假设Message定义如下

// An highlighted block
syntax = "proto2";
package Test_econd;

message Test2 {
  optional string b = 2;
}

则当将Test2的b设置为testing时,其编码过程如下:

  1. 字符串的类型为type=2, 数字域为2,数字域<<3
  2. 然后将其结果 | type
  3. 用可变字节表示字符串的长度,即07
  4. testing被编码为utf8类型的 74 65 73 74 69 6e 67

protobuf C++相关编程

  1. proto文件的实现,我编写测试用例命名为test.proto
    其实现如下:
// An highlighted block
syntax = "proto2";

package Test_econd;

message Test1 {
    optional int32 a = 1;
    optional string str = 2;
}

在相应的目录下执行:
protoc -I = ./src --cpp_out == ./src ./src/test.proto

  1. 在src中生成test.pb.h和test.pb.cc文件
    在这里插入图片描述
  2. 建立write_pb.h文件,如下
// An highlighted block
#ifndef QIN_WRITE_PB_H
#define QIN_WRITE_PB_H
#include <fstream>
#include <iostream>



#include "test.pb.h"

void PromptForTest(Test_econd::Test1* test1);
#endif
  1. write_pb.cpp实现如下
// An highlighted block
//
//
//
#include "write_pb.h"

void PromptForTest(Test_econd::Test1* test1) {
    std::cout << "请输入一个数:" << std::endl;
    int id;
    std::cin >> id;
    test1->set_a(id);
    std::cin.ignore(256, '\n');

    std::cout << "请输入一个字符串" << std::endl;
    std::string str;
    std::getline(std::cin, str);
    test1->set_str(str);
}
  1. main函数实现为
// An highlighted block
//
//
//
#include <google/protobuf/text_format.h>
#include <google/protobuf/message.h>
#include "base/base64.h"

#include "write_pb.h"

int main(int argc, char* argv[]){
    // Verify that the version of the library that we linked against is
  // compatible with the version of the headers we compiled against.
    GOOGLE_PROTOBUF_VERIFY_VERSION;
    if (argc != 2) {
        std::cerr << "Usage : " << "错误" << std::endl;
        return -1;
    }
    Test_econd::Test1 test1_1;

    PromptForTest(&test1_1);
    {
        // std::fstream output(argv[1], std::ios::out | std::ios::trunc | std::ios::binary);
        std::string output;
        if (!test1_1.SerializeToString(&output)) {
            std::cerr << "序列化失败:" << std::endl;
            return -1;
        }
        // base64编码
       
        std::cout << "序列化结果:" << output << std::endl;
        
    }
    
    // 解析字符串
    {
        google::protobuf::Message* test = new Test_econd::Test1;
        std::string text_string;
        google::protobuf::TextFormat::PrintToString(*test, &text_string);
        std::cout << "解析的文本为:" << text_string.size() << std::endl;
    }
    google::protobuf::ShutdownProtobufLibrary();
    return 0;
}

验证输出结果为:
在这里插入图片描述

[1] [ProtoBuffers] (https://developers.google.com/protocol-buffers/docs/proto)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qls315

感觉好可打赏几毛钱增强更新动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值