Protobuf详解以及入门指南

Protobuf 概述

Protobuf(Protocol Buffers)协议是由 Google 开发的二进制序列化格式技术它提供了一种高效、简洁和可扩展的方式来序列化和交换数据,Protobuf 的主要优点包括:

  • 高效性: Protobuf 序列化后是以二进制存储,具有size小,读写高效的特别,并且序列化和反序列化的速度更快,这对于性能敏感的应用非常有益。
  • 简洁性:Protobuf 使用一种定义消息格式的语法,它允许定义字段类型、顺序和规则(消息结构更加清晰和简洁)
  • 兼容性:
    1. 版本兼容:Protobuf 支持向前和向后兼容的版本控制,使得在消息格式发生变化时可以更容易地处理不同版本的通信。
    2. 语言兼容:Protobuf 可以支持目前几乎所有的主流语言,比如C/C++/Python/Java 等等,非常方便跨语言的数据传输

更详细描述,可以访问Procol BUffer官网

Protobuf 安装与环境配置

git clone https://github.com/protocolbuffers/protobuf
cd protobuf && ./
make -j64
sudo make install

默认安装路径是/usr/local下面,安装完成后,执行protoc --version进行检查
如果出现libprotoc.so动态库找不到,可以配置LD_LIBRARY_PATH,或者将按照的lib添加到/etc/ld.so.conf

Protobuf 语言介绍

首先需要创建一个.proto后缀的文件。

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 results_per_page = 3;
}
  • 第一行需要明确使用的proto 语法(syntax = “proto3”😉
  • 接下来就是定义自己的用于交互的SearchRequest 消息体,并使用(value/key)来定义内容

Scalar Value Types

.proto TypeC/C++JavaPythonGoC#Note
doubledoubledoublefloatfloat64double
floatfloatfloatfloatfloat32float
int32intintintint32int
int64longlongint/long[4]int64long
uint32unsigned intint[2]int/long[4]uint32uint
uint64unsigned longlong[2]int/long[4]uint64ulong
sint32signed intintintint32int
sint64signed longlongint/long[4]int64long
fixed32uint32int[2]int/long[4]uint32uint
fixed64uint64long[2]int/long[4]uint64ulong
sfixed32int32intintint32intAlways 4 bytes.
sfixed64int64longinint64longAlways 8 bytes.
boolboolbooleanboolboolbool
stringstringStringstrstringstringA string must always contain UTF-8 encoded or 7-bit ASCII text, and cannot be longer than 232.
bytesstringByteStringstr (Python 2) bytes (Python 3)[]byteByteStringMay contain any arbitrary sequence of bytes no longer than 232.

[2] 在Java中,无符号32位和64位整数使用有符号整数表示,顶部位只是存储在符号位中

[4] 64位或无符号32位整数在解码时总是表示为long,但如果在设置字段时给出int,则可以表示为int。在所有情况下,值必须适合设置时表示的类型。

Default Values

  • string/bytes: 默认值为空字符
  • bool: 默认值为false
  • numeric types: 默认值为0
  • enums: 第一个定义的枚举遍历,默认值为0
  • message: 表示not set

Specifying Field Labels

  • optional: 一个可选的变量,只有两种状态:
    • set, 显式地设置一个用于值
    • unset: 表示没有设置值,返回的是默认值
  • repeated: 表示的是该变量被复制零份或多份,并且用默认值进行填充
  • map: 定义一个key

Reserved Field Numbers

如果操作不当,删除字段可能会导致严重的问题。
当不再需要一些field或者所有的时,期望它可以从原来的field中删除掉,则必须使用reserve来标识

message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}
  1. 预留feild number:2, 15, 9 to 11, 其中9 to 11是递归遍历,标识9,10,11
  2. 还可以通过标识特殊字段来进行表示需要预留的字段

Enumerations 枚举类

enum Corpus {
  CORPUS_UNSPECIFIED = 0;
  CORPUS_UNIVERSAL = 1;
  CORPUS_WEB = 2;
  CORPUS_IMAGES = 3;
  CORPUS_LOCAL = 4;
  CORPUS_NEWS = 5;
  CORPUS_PRODUCTS = 6;
  CORPUS_VIDEO = 7;
}

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 results_per_page = 3;
  Corpus corpus = 4;
}

Proto 与 JSON对比

proto3JSONJSON examplenote
messageobject{“fooBar”: v, “g”: null, …}
enumstring“FOO_BAR”
map<K,V>object{“k”: v, …}
repeated Varray[v, …]支持null
booltrue/falsetrue, false
stringstring“Hello World!”
bytesbase64 string“YWJjMTIzIT8kKiYoKSctPUB+”
int32, fixed32, uint32number1, -10, 0
int64, fixed64, uint64string“1”, “-10”
float, doublenumber1.1, -10.0, 0, “NaN”, “Infinity”
Anyobject{“@type”: “url”, “f”: v, … }
Timestampstring“1972-01-01T10:00:20.021Z”
Durationstring“1.000340012s”, “1s”
Structobject{ … }
Wrapper typesvarious types2, “2”, “foo”, true, “true”, null, 0, …
FieldMaskstring“f.fooBar,h”
ListValuearray[foo, bar, …]
Valuevalue
NullValuenull
Emptyobject{}

Protobuf 文件创建

创建文件test.proto

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 results_per_page = 3;
}

执行protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto 便可以将proto语言转成c++语言

protoc -I=./ --cpp_out=./ ./test.proto

# 输出.cc 和.h 文件
>> test.pb.cc
>> test.pb.h

打开.h文件可以看到对应变量的操作

class SearchRequest : public ::google::protobuf::Message {
//...
  // string query = 1;
  void clear_query();
  static const int kQueryFieldNumber = 1;
  const ::std::string& query() const;
  void set_query(const ::std::string& value);
  #if LANG_CXX11
  void set_query(::std::string&& value);
  #endif
  void set_query(const char* value);
  void set_query(const char* value, size_t size);
  ::std::string* mutable_query();
  ::std::string* release_query();
  void set_allocated_query(::std::string* query);

  // int32 page_number = 2;
  void clear_page_number();
  static const int kPageNumberFieldNumber = 2;
  ::google::protobuf::int32 page_number() const;
  void set_page_number(::google::protobuf::int32 value);

  // int32 results_per_page = 3;
  void clear_results_per_page();
  static const int kResultsPerPageFieldNumber = 3;
  ::google::protobuf::int32 results_per_page() const;
  void set_results_per_page(::google::protobuf::int32 value);
//...
};

开发人员可以通过变量query()来获取值,通过set_query(const ::std::string& value)来设置值

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值