参考:
message
定义消息message 消息名 {
定义字段
}
message 父消息名 {
message 子消息名 {
}
}
字段规则 字段类型 字段名 = 字段编号
https://developers.google.com/protocol-buffers/docs/proto#scalar
enum
枚举 类型enmu 枚举名 {
枚举常量 = 值;
}
Oneof
类型Oneof多个成员字段,只用一块内存,最多一个字段有值
使用 case() 或 WhichOneof 方法去获取被赋值的字段,具体使用哪个方法取决于具体的编程语言。
oneof 里面的字段使用的编号和外部的字段编号同级的
message 消息名 {
// 给一个字段赋值,其他字段就变为空
oneof oneof名 {
字段1 = 1;
字段2 = 2;
}
}
https://forrestsu.github.io/posts/go/golang-pb3-oneof/
Maps
类型map map_field = N;
https://developers.google.com/protocol-buffers/docs/overview#data-types
https://protobuf.dev/reference/protobuf/google.protobuf/
常用以下的包
// 用于实现一些高级的功能,还提供了一些工具和库。如 RPC 通信和分布式系统, grpc.health.v1.Health 服务
package google.protobuf
// 用于存储一些常见的数据类型和数据结构。例如 Date、TimeOfDay、Timestamp、LatLng、Money 等等。
package google.type
google.type.Date:用于表示日期,包括年、月、日三个字段。
google.type.TimeOfDay:用于表示一天中的时间,包括小时、分钟、秒钟和纳秒四个字段。
google.protobuf.Timestamp:用于表示时间戳,包括秒数和纳秒数两个字段。
google.type.LatLng:用于表示地理坐标,包括纬度和经度两个浮点数字段。
google.type.Money:用于表示货币金额,包括金额和货币类型两个字段。
google.type.PostalAddress:用于表示邮政地址,包括国家、省份、城市、邮政编码、街道地址等字段
Wrapper 类型是 Protobuf 3 中的一个特殊消息类型,用于包装原始类型的值。它允许您将原始类型的值存储在一个消息中,并将其序列化为二进制数据流。
作用
:避免了必须使用默认值来表示缺失值的问题。它也可以用于处理某些类型系统中的空值或缺失值
syntax = "proto3";
import "google/protobuf/wrappers.proto";
message MyMessage {
google.protobuf.Int32Value my_int_field = 1;
}
my_int_field 字段是一个 Int32Value 类型,它包装了一个 int32 类型的值。当您将该消息序列化为二进制数据流时,该字段的值将被正确地编码为一个单一的整数值。在接收方收到消息后,您可以使用 .value() 方法来获取实际的 int32 值。
syntax = "proto3";
package google.protobuf;
//使用 Int32Value 消息来包装一个 int32 类型的值,并将其序列化为二进制数据流:
message Int64Value {
int64 value = 1;
}
message DoubleValue {
double value = 1;
}
message FloatValue {
float value = 1;
}
message UInt64Value {
uint64 value = 1;
}
message Int32Value {
int32 value = 1;
}
message UInt32Value {
uint32 value = 1;
}
message BoolValue {
bool value = 1;
}
message StringValue {
string value = 1;
}
message BytesValue {
bytes value = 1;
}
required
: 必输
optional
:可选,零个或一个这个字段(但不能超过一个)。
default
默认值
optional int32 字段名 = 编号 [default = 默认值];
repeated
:动态数组
reserved
保留字段
//如果将来有任何用户尝试使用这些 保留字段标识符,protocol buffer编译器会警告。
message 消息名 {
reserved 保留字段
}
message Foo {
字段1 = 1;
字段2 = 2;
// 保留几个扩展字段
extensions 3 to 5;
}
// 扩展字段
extend Foo {
字段3 = 3;
字段4 = 4;
字段5 = 5;
}
确保两个用户不会使用相同的字段编号将扩展名添加到相同的消息类型,否则可能会导致数据的不一致
标识号产生的规则中应该避开[19000-19999]之间的数字,因为这些已经被Protocol Buffers实现中预留了。
文件级选项,消息级别的选项,字段级选项
options 有内置也有自定义的
内置option 有多种类型
比如 fileOption, fieldOption, methodOption 等等
定义格式
可以写在枚举类型、枚举值、oneof字段、服务类型、服务方法
// 文件选项
option option名 = 常量 ;
message Foo {
// 消息选项
option 消息选项名 = 常量;
// fieldOptions 字段选项
[ repeated ] type fieldName = fieldNumber [ [ 字段选项名 = 常量 ] ] ;
}
选项是由google/protobuf/descriptor.proto
文件中的消息定义的,
通过extend 扩展
这些消息 就能定义自己的option
import "google/protobuf/descriptor.proto";
extend google.protobuf.MethodOptions {
HttpRule http = 72295728;
}
service 服务名 {
rpc 方法名(入参消息) returns (出参消息);
}
https://developers.google.com/protocol-buffers/docs/proto3#scalar
Any包含任意序列化消息,可以保存任意 proto3 消息,类似于proto2 的扩展消息
import "google/protobuf/any.proto";
message 消息名 {
repeated google.protobuf.Any 字段名 = 1;
}
把 optional
可选 改名为 singular
单数
移除了required
必输
移除了 default
默认值。proto3 中字段的默认值由系统决定
扩展:
Extensions
扩展的支持,新增了 Any 类型解析过程中,对未定义字段的处理
https://developers.google.com/protocol-buffers/docs/tutorials
我们将要使用的示例是一个非常简单的“地址簿”应用程序,它可以在文件中读取和写入人们的联系方式。地址簿中的每个人都有一个姓名、一个 ID、一个电子邮件地址和一个联系电话号码。
使用protocol buffers,您可以编写.proto要存储的数据结构的描述。
https://github.com/protocolbuffers/protobuf/tree/main/examples
要创建“地址簿”应用程序,您需要从 .proto文件开始。
文件中的定义.proto很简单:为要序列化的每个数据结构添加一条消息,然后为消息中的每个字段指定名称和类型。
addressbook.proto
syntax = "proto3";
package tutorial;
import "google/protobuf/timestamp.proto";
option go_package = "github.com/protocolbuffers/protobuf/examples/go/tutorialpb";
package
import
Options
消息只是包含一组类型字段的聚合。
许多标准的简单数据类型可用作字段类型,包括bool、int32、 float、double和string。
您还可以通过使用其他消息类型作为字段类型来为您的消息添加更多结构。
message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
google.protobuf.Timestamp last_updated = 5;
}
// Our address book file is just one of these.
message AddressBook {
repeated Person people = 1;
}
编译成go代码结构体为:
type AddressBook struct {
People []*Person
}
type Person struct {
Name string
Id int32
Email string
Phones []*PhoneNumber
LastUpdated *timestamppb.Timestamp
}
type PhoneNumber struct {
Number string
Type PhoneType
}
// go语言并没有提供enum的定义,使用const来模拟枚举类型
type PhoneType int32
const (
MOBILE Person_PhoneType = 0
HOME Person_PhoneType = 1
WORK Person_PhoneType = 2
)
......
protoc -I proto_path --go_out=xxx
protoc -I proto_path --java_out=xxx
protoc -I proto_path --go-grpc_out=xxx
protoc
与 对应语言插件
结合,生成桩代码
命令 | 对应插件 | 生成文件 |
---|---|---|
–go_out | protoc-gen-go 插件; | *.pb.go |
–java_out | protoc-gen-java 插件; | *.java |
–go-grpc_out | protoc-gen-go-grpc 插件; | |
–*_out | protoc-gen-* 插件; |
github.com/golang/protobuf
与 google.golang.org/protobuf
如果在网上发现有些教程让下载github.com/golang/protobuf, 有些让下载google.golang.org/protobuf。不用懵逼,根据实际项目情况决定,
github.com/golang/protobuf 已弃用 ,建议新代码使用该google.golang.org/protobuf模块。
https://pkg.go.dev/github.com/golang/protobuf
https://pkg.go.dev/google.golang.org/protobuf
protoc是protobuf文件(.proto)的编译器,
可结合各种语言的插件 将 .proto 文件编译成 C、C++、Golang、Java、Python、PHP 等多种语言的代码 (包含数据类型定义、调用接口等)。
brew install protobuf ##会拉去最新版本
git clone https://github.com/protocolbuffers/protobuf
# v3.6.0+以上版本支持map解析,syntax=2、3消息序列化后是二进制兼容的,用root执行以下命令
cd protobuf
git checkout v3.6.1.3
./autogen.sh
./configure
make -j8
make install
go语言的编译插件
# 旧
go install github.com/golang/protobuf/protoc-gen-go@latest
# 新
go install google.golang.org/protobuf/cmd/[email protected]