先贴上Protobuf的资料:
Protobuf官方资料:Developer Guide
Protobuf gitbub地址:protocolbuffers/protobuf
ProtoBuf3官方文档:
Language Guide (proto3) | Protocol Buffers | Google Developers
ProtoBuf3 Go语言教程:
Protocol Buffer Basics: Go | Protocol Buffers | Google Developers
注意:Proto2和Proto3其语法定义会有很大的差别,初学者建议学习ProtoBuf3,
本文将详细讲解如下问题:
ProtoBuf协议是什么协议,优缺点是啥?为什么它比json、XML效率都要高?
在go语言中怎么实现ProtobufBuf协议 ?
如何生成和定义proto文件?
怎么使用ProtoBuf编译器编译proto文件,自动生成go代码?
怎么使用Go第三方库实现ProtoBuf编程?
ProtoBuf是通过对传输字段的名称、顺序进行预定义,从而在传输结构中只需要顺序的记录每个字段的类型标签和二进制值,所以性能比JSON、XML强很多。
相对于json和xml解析方式,快速高效非常多,因为他会编译成一种二进制文件
能通过Protobuf协议定义一种文件,一种机制,自动生成go文件,生成结构体
因为Protobuf采用的是二进制格式进行编译。
开发者面对二进制格式的Protobuf,没有办法知道所对应的真实的数据结构,因此在使用Protobuf协议传输时,必须配备对应的proto配置文件。
可以在如下地址: https://github.com/protocolbuffers/protobuf/releases 选择适合自己系统的Proto编译器程序进行下载并解压,
下载解压成功后,需要将bin文件夹路径添加到环境变量中,如下图所示。
添加环境变量:
查看版本:protoc --version
protoc --version
出现上述说明编译器安装好了
go get下载命令:go get github.com/golang/protobuf/protoc-gen-go (二选一)
git 下载命令:git clone https://github.com/golang/protobuf.git
如下是java版本实现:
下载地址: protobuf-java-3.20.1.zip
具体实现:https://zhuanlan.zhihu.com/p/503800248
Go实现
注意:使用protobuf协议,必须严格遵循protobuf的语法。
1、创建golang项目
2、创建proto文件
3、编写protobuf协议文件
语法介绍:https://developers.google.cn/protocol-buffers/docs/gotutorial
4、编译proto文件 (基于protoc编译器)
命令:protoc --go_out= .proto文件的路径
会生成如下文件:(proto编译器编译后的)
注意:如下代码都是ProtoBuf协议编译器编译后自动生成的,包括go结构体等...
//版本
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1-devel
// protoc v3.20.1
// source: order.proto
package example
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
//定义消息对象
type Order struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
//消息字段 = 字段类型 +字段名 +标识号(新版本不需要修饰符)
OrderId int32 `protobuf:"varint,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"`
Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` //2代表字段顺序
TimeStamp string `protobuf:"bytes,3,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"`
}
func (x *Order) Reset() {
*x = Order{}
if protoimpl.UnsafeEnabled {
mi := &file_order_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Order) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Order) ProtoMessage() {}
func (x *Order) ProtoReflect() protoreflect.Message {
mi := &file_order_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Order.ProtoReflect.Descriptor instead.
func (*Order) Descriptor() ([]byte, []int) {
return file_order_proto_rawDescGZIP(), []int{0}
}
func (x *Order) GetOrderId() int32 {
if x != nil {
return x.OrderId
}
return 0
}
func (x *Order) GetNum() int64 {
if x != nil {
return x.Num
}
return 0
}
func (x *Order) GetTimeStamp() string {
if x != nil {
return x.TimeStamp
}
return ""
}
var File_order_proto protoreflect.FileDescriptor
var file_order_proto_rawDesc = []byte{
0x0a, 0x0b, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x52, 0x0a,
0x05, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49,
0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03,
0x6e, 0x75, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d,
0x70, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_order_proto_rawDescOnce sync.Once
file_order_proto_rawDescData = file_order_proto_rawDesc
)
func file_order_proto_rawDescGZIP() []byte {
file_order_proto_rawDescOnce.Do(func() {
file_order_proto_rawDescData = protoimpl.X.CompressGZIP(file_order_proto_rawDescData)
})
return file_order_proto_rawDescData
}
var file_order_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_order_proto_goTypes = []interface{}{
(*Order)(nil), // 0: Order
}
var file_order_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_order_proto_init() }
func file_order_proto_init() {
if File_order_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_order_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Order); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_order_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_order_proto_goTypes,
DependencyIndexes: file_order_proto_depIdxs,
MessageInfos: file_order_proto_msgTypes,
}.Build()
File_order_proto = out.File
file_order_proto_rawDesc = nil
file_order_proto_goTypes = nil
file_order_proto_depIdxs = nil
}
5、使用编译后的文件 ---> 包名.消息对象
(错误示例:不要使用proto作为文件名,会和标准库冲突)
注意:编译到时候=中间没有空格 protoc --go_out=. order.proto
基础语法,消息嵌套
具体使用:
想要“改进”协议缓冲区的定义。并且想要我们的缓冲区向后兼容,向前兼容,那么你需要遵守一些规则。
在新版本的协议缓冲区中:
标识号最小是从1开始,最大是2^99-1(536870911),
不能使用19900 ~ 19999标识号,这是ProtoBuf协议内部的预留。
注意:
好啦,上述就是ProtoBuf协议的介绍。