> 文章列表 > ProtocolBuffer入门和使用

ProtocolBuffer入门和使用

ProtocolBuffer入门和使用

<<<<<<< HEAD

基础

入门

img

优势

  • protocol buffer主要用于结构化数据串行化的灵活、高效、自动的方法(简单来说就是结构化数据的可串行化传输,类似JSON、XML等)。
    • 比XML解析更快:解析的层数更少,所以更快
    • 比XML数据包体积更小:采用varint编码
  • 用protocol编译器生成特定语言的源代码,实现数据模型跨语言串行化;
    • 使用对应语言的生成器+Protocol编译器即可编译出对应语言的代码
  • protocol是grpc推荐的序列化和反序列语言、grpc又是k8s推荐的rpc方式;

文档

  • 中文:GitHub - lixiangyun/protobuf_doc_ZH_CN: 中文手册
  • 官方:官方文档

基础语法

  • 注释使用//
  • 字段默认值为零值、可以通过[default = 10]自定义默认值
  • 支持枚举类型
  • extend特性来让你声明一些Tags值来供第三方扩展使用、或者弃用该字段
  • 数据模式:只需要通过message 数据模式名{}字段
  • 每个字段由:限制类型+类型+字段名+编号确定
    • 编号(顺序号)
      • **字段编号在1-15之间占用一个字节进行编码,**16-2047范围内的占用两个字节进行编码。因此在进行字段编码的时候最好将常用的字段用1-15进行编码,这样可以节省占用的空间
  • 生成器选项
    • optimize_for (file option): 可以设置的值有**SPEED, CODE_SIZE, 或 LITE_RUNTIME**. 不同的选项会以下述方式影响C++, Java代码的生成
      • SPEED (默认): protocol buffer编译器将会生成序列化,语法分析和其他高效操作消息类型的方式.这也是最高的优化选项.确定是生成的代码比较大.
      • CODE_SIZE: protocol buffer编译器将会生成最小的类,但是比SPEED运行速度要慢
      • LITE_RUNTIME: protocol buffer编译器将会生成只依赖"lite" runtime library (libprotobuf-lite instead of libprotobuf)的类. lite运行时库比整个库更小但是删除了例如descriptors 和 reflection等特性. 这个选项通常用于手机平台的优化.

核心概念

  • varintzigzag编码:Protocol默认使用varint编码,负数使用zigzag编码
    • varint编码:通过首位标识是否还有数据**,每个字节首位表示后面是否还有字节,而后7位表示数据。**
      • ProtocolBuffer入门和使用
    • zigzag编码:由于负数不能使用varint编码,所以首先按照下表中的规律,将数据全部转化成正数,然后再用varint进行编码。
      • ProtocolBuffer入门和使用
  • .proto文件:保存数据模型,可以导出并且被外部.proto文件导入,相当于一个xml文件;
  • 数据模型:在Protocol中数据模型的定义主要包括
    • 普通field
    • 数据模型嵌套
  • field
    • 限制类型:在Protocol中主要有三种类型:
      • required:必须
      • optional:可选
      • repeated:可重复(类似数组)
    • 顺序号(tags)
      • **每一个字段都有一个独一无二的数值类型的Tag;**不允许重复、不应该也不要在更新时删除无效字段然后或者替换新字段使用该顺序号
    • 字段类型
message test {//必须有字段,默认为lili;顺序号为1required string name = 1 [DEFAULT = "lili"];//可选字段optional string password = 2;//数组repeated int32 alias = 3;
}

Field

  • 给不同的元素以相同的alias,但是需要指定option allow_alias = true;

字段类型映射表

字段类型转换表(基本和go的内置数据类型是一一映射,除了没有map)

Protocol Java Go
int32 int int32
int64 long int64
double double float64
float float float32
uint32、uint64 uint、ulong uint32、uint64
bool boolean bool
string String string
map HashMap map
bytes ByteString []byte
sfixed32\\64、fixed32\\64 int\\long、uint\\ulong int32\\64、uint32\\64
  • Map 字段不能使用repeated关键字修饰

枚举类型

  • 枚举类型的第一个值初始化为0,
  • 在message中使用枚举类型,必须要给定一个为0的值
message SearchRequest {option allow_alias = true;string query = 1;int32 page_number = 2;int32 result_per_page = 3;enum Corpus {UNIVERSAL = 0;WEB = 1;IMAGES = 2;LOCAL = 3;NEWS = 4;PRODUCTS = 5;VIDEO = 6;}Corpus corpus = 4;
}

方法

  • Protocol定义方法(函数)的方式为:service serviceName{}
  • 定义rpc方法:rpc methodName (参数类型) returns (返回值类型)
message requestMessage {optional int32 code = 1;optional string message = 2;
}message responseMessage {optional int32 code = 1;optional string message = 2;
}service UserService {rpc test(requestMessage) returns (responseMessage);
}

import机制

  • 导入数据模型时,如果不在一个文件需要通过import导入

  • import必须指定在执行protocol命令的目录为基点,否则需要通过import public机制导入

    • 编译器就会在某些固定目录下查询import的proto文件(具体在命令行编译的时候,由-I/—proto_path指定)\\
    • 如果上述路径找不到,编译器会在调用路径进行查找。通常将—proto_path设置为项目的根目录
    import "xxx"
    import public "xxx"
    

命令

  • proto --help:获取帮助
  • proto --XXX_out:将proto文件编译为xxx类型的源代码*(go语言需要安装插件才能实现)*
    • --go-grpc_out: 安装go-grpc插件后,可以将proto文件生成go的grpc代码
protoc --go_out=输出目录(数据模型) --go-grpc_out=输出目录(grpc方法) *.proto #输出文件:*.proto表示输出全部proto文件

使用

基本使用

  • 首先安装Protocol buffer编译器
  • 安装对应语言生成器

go例子

//protoc版本
syntax = "proto3";//包名
package grpc;//输出包
option go_package ="../grpc";//数据模型
message requestMessage {optional int32 code = 1;optional string message = 2;
}message responseMessage {optional int32 code = 1;optional string message = 2;
}//grpc方法
service UserService {rpc test(requestMessage) returns (responseMessage);
}

输出go代码

#在当前文件目录下执行
protoc -I=. --go_out=. --go-grpc_out=. ./*.proto

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHRIablp-1681966664637)(ProtocolBuffer.assets/image-20220614102631349.png)]

Proto3

ProtocolBuffer入门和使用

内置数据结构

timestamp和duration

  • 时间类型

any

  • 任意类型,所有实现了proto.Message的结构体;所有消息都会自动实现该接口;
    • 在go中可以通过anypb.Any使用[]byte类型的默认实现
  • 自定义实现了proto.Message接口的结构体

empty

  • 空类型,在没有参数或者返回值的方法需要类型为指定为empty

Oneof

  • oneof内的field只能有一个字段填充
  • oneof字段就像可选字段, 除了它们会共享内存设置其中一个字段会清除其它字段。
  • 使用case()或者WhichOneof() 方法检查哪个oneof字段被设置
//数据模型
message requestMessage {//普通字段optional int32 code = 1;//map字段  map<string,google.protobuf.Any> other = 10;//内置字段google.protobuf.Timestamp sendTime = 11;google.protobuf.Duration createTime = 12;optional google.protobuf.Any data = 3;//oneofoneof testOneof {string name = 4;string alais = 9;}
}

内置API

https://cloud.google.com/apis/design/glossary

=======

基础

入门

img

优势

  • protocol buffer主要用于结构化数据串行化的灵活、高效、自动的方法(简单来说就是结构化数据的可串行化传输,类似JSON、XML等)。
    • 比XML解析更快:解析的层数更少,所以更快
    • 比XML数据包体积更小:采用varint编码
  • 用protocol编译器生成特定语言的源代码,实现数据模型跨语言串行化;
    • 使用对应语言的生成器+Protocol编译器即可编译出对应语言的代码
  • protocol是grpc推荐的序列化和反序列语言、grpc又是k8s推荐的rpc方式;

文档

  • 中文:GitHub - lixiangyun/protobuf_doc_ZH_CN: 中文手册
  • 官方:官方文档

基础语法

  • 注释使用//
  • 字段默认值为零值、可以通过[default = 10]自定义默认值
  • 支持枚举类型
  • extend特性来让你声明一些Tags值来供第三方扩展使用、或者弃用该字段
  • 数据模式:只需要通过message 数据模式名{}字段
  • 每个字段由:限制类型+类型+字段名+编号确定
    • 编号(顺序号)
      • **字段编号在1-15之间占用一个字节进行编码,**16-2047范围内的占用两个字节进行编码。因此在进行字段编码的时候最好将常用的字段用1-15进行编码,这样可以节省占用的空间
  • 生成器选项
    • optimize_for (file option): 可以设置的值有**SPEED, CODE_SIZE, 或 LITE_RUNTIME**. 不同的选项会以下述方式影响C++, Java代码的生成
      • SPEED (默认): protocol buffer编译器将会生成序列化,语法分析和其他高效操作消息类型的方式.这也是最高的优化选项.确定是生成的代码比较大.
      • CODE_SIZE: protocol buffer编译器将会生成最小的类,但是比SPEED运行速度要慢
      • LITE_RUNTIME: protocol buffer编译器将会生成只依赖"lite" runtime library (libprotobuf-lite instead of libprotobuf)的类. lite运行时库比整个库更小但是删除了例如descriptors 和 reflection等特性. 这个选项通常用于手机平台的优化.

核心概念

  • varintzigzag编码:Protocol默认使用varint编码,负数使用zigzag编码
    • varint编码:通过首位标识是否还有数据**,每个字节首位表示后面是否还有字节,而后7位表示数据。**
      • ProtocolBuffer入门和使用
    • zigzag编码:由于负数不能使用varint编码,所以首先按照下表中的规律,将数据全部转化成正数,然后再用varint进行编码。
      • ProtocolBuffer入门和使用
  • .proto文件:保存数据模型,可以导出并且被外部.proto文件导入,相当于一个xml文件;
  • 数据模型:在Protocol中数据模型的定义主要包括
    • 普通field
    • 数据模型嵌套
  • field
    • 限制类型:在Protocol中主要有三种类型:
      • required:必须
      • optional:可选
      • repeated:可重复(类似数组)
    • 顺序号(tags)
      • **每一个字段都有一个独一无二的数值类型的Tag;**不允许重复、不应该也不要在更新时删除无效字段然后或者替换新字段使用该顺序号
    • 字段类型
message test {//必须有字段,默认为lili;顺序号为1required string name = 1 [DEFAULT = "lili"];//可选字段optional string password = 2;//数组repeated int32 alias = 3;
}

Field

  • 给不同的元素以相同的alias,但是需要指定option allow_alias = true;

字段类型映射表

字段类型转换表(基本和go的内置数据类型是一一映射,除了没有map)

Protocol Java Go
int32 int int32
int64 long int64
double double float64
float float float32
uint32、uint64 uint、ulong uint32、uint64
bool boolean bool
string String string
map HashMap map
bytes ByteString []byte
sfixed32\\64、fixed32\\64 int\\long、uint\\ulong int32\\64、uint32\\64
  • Map 字段不能使用repeated关键字修饰

枚举类型

  • 枚举类型的第一个值初始化为0,
  • 在message中使用枚举类型,必须要给定一个为0的值
message SearchRequest {option allow_alias = true;string query = 1;int32 page_number = 2;int32 result_per_page = 3;enum Corpus {UNIVERSAL = 0;WEB = 1;IMAGES = 2;LOCAL = 3;NEWS = 4;PRODUCTS = 5;VIDEO = 6;}Corpus corpus = 4;
}

方法

  • Protocol定义方法(函数)的方式为:service serviceName{}
  • 定义rpc方法:rpc methodName (参数类型) returns (返回值类型)
message requestMessage {optional int32 code = 1;optional string message = 2;
}message responseMessage {optional int32 code = 1;optional string message = 2;
}service UserService {rpc test(requestMessage) returns (responseMessage);
}

import机制

  • 导入数据模型时,如果不在一个文件需要通过import导入

  • import必须指定在执行protocol命令的目录为基点,否则需要通过import public机制导入

    • 编译器就会在某些固定目录下查询import的proto文件(具体在命令行编译的时候,由-I/—proto_path指定)\\
    • 如果上述路径找不到,编译器会在调用路径进行查找。通常将—proto_path设置为项目的根目录
    import "xxx"
    import public "xxx"
    

命令

  • proto --help:获取帮助
  • proto --XXX_out:将proto文件编译为xxx类型的源代码*(go语言需要安装插件才能实现)*
    • --go-grpc_out: 安装go-grpc插件后,可以将proto文件生成go的grpc代码
protoc --go_out=输出目录(数据模型) --go-grpc_out=输出目录(grpc方法) *.proto #输出文件:*.proto表示输出全部proto文件

使用

基本使用

  • 首先安装Protocol buffer编译器
  • 安装对应语言生成器

go例子

//protoc版本
syntax = "proto3";//包名
package grpc;//输出包
option go_package ="../grpc";//数据模型
message requestMessage {optional int32 code = 1;optional string message = 2;
}message responseMessage {optional int32 code = 1;optional string message = 2;
}//grpc方法
service UserService {rpc test(requestMessage) returns (responseMessage);
}

输出go代码

#在当前文件目录下执行
protoc -I=. --go_out=. --go-grpc_out=. ./*.proto

ProtocolBuffer入门和使用

Proto3

ProtocolBuffer入门和使用

内置数据结构

timestamp和duration

  • 时间类型

any

  • 任意类型,所有实现了proto.Message的结构体;所有消息都会自动实现该接口;
    • 在go中可以通过anypb.Any使用[]byte类型的默认实现
  • 自定义实现了proto.Message接口的结构体

empty

  • 空类型,在没有参数或者返回值的方法需要类型为指定为empty

Oneof

  • oneof内的field只能有一个字段填充
  • oneof字段就像可选字段, 除了它们会共享内存设置其中一个字段会清除其它字段。
  • 使用case()或者WhichOneof() 方法检查哪个oneof字段被设置
//数据模型
message requestMessage {//普通字段optional int32 code = 1;//map字段  map<string,google.protobuf.Any> other = 10;//内置字段google.protobuf.Timestamp sendTime = 11;google.protobuf.Duration createTime = 12;optional google.protobuf.Any data = 3;//oneofoneof testOneof {string name = 4;string alais = 9;}
}

内置API

https://cloud.google.com/apis/design/glossary

知识百科