Go --- protobuf的介绍和使用

简介: Go --- protobuf的介绍和使用

介绍

protobuf (protocol buffer) 是谷歌内部的混合语言数据标准

protocol buffers 是一种与语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML(应该只是传输数据的功能和数据结构化的类比)。

序列化:是将对象的状态信息转换为可以存储或传输的形式的过程,序列化后的数据要确保能通过反序列化后还原出来

优点:

  • 语言无关,平台无关
    Protobuf支持Java, C++, Python等多种语言,支持多个平台。
  • 高效
    比XML更小(3~10倍),更快(20 ~ 100倍),更为简单。
  • 扩展性,兼容性好
    你可以更新数据结构,而不影响和破坏原有的旧程序。

安装

二进制可执行文件(命令)

安装地址:

https://github.com/protocolbuffers/protobuf/releases

下载自己系统需要的压缩包

就比如我的系统时win11,64位的,下载的就是这个

然后将解压后文件的/bin目录添加到环境变量中

打开CMD或是powershell,查看版本号protoc --version

如果有输出就说明添加成功了。

安装解析工具

如果是在go语言中使用,还需要下载一个解析.proto文件的工具

go get github.com/golang/protobuf/protoc-gen-go

它会将.proto文件转为.pb.go文件。

安装插件

如果想让Goland识别出.proto文件还需要安装一个插件

File–>Settings–>Plugins

使用

新建一个项目,在项目下新建一个文件夹用来存放.proto文件

user.proto文件

// 指定当前版本
syntax = "proto3";
// option go_package = "path;name";
// path表示生成的go文件存放地址,会自动生成目录
// name 表示生成go文件所属包名
option go_package = "../service";
// 指定文件生成出来的package
package service;
message User {
  string username = 1;
  int32 age = 2;
  optional string password = 3;
  repeated bool sex = 4;
}

在pbfile目录下执行

protoc --go_out=./ user.proto

就会发现生成了一个

user.pb.go文件(这里的都是默认生成的,不要改,生成的时需要导入依赖)

// 指定当前版本
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//     protoc-gen-go v1.26.0
//     protoc        v3.21.1
// source: user.proto
// 指定文件生成出来的package
package service
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 User struct {
   state         protoimpl.MessageState
   sizeCache     protoimpl.SizeCache
   unknownFields protoimpl.UnknownFields
   Username string  `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
   Age      int32   `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
   Password *string `protobuf:"bytes,3,opt,name=password,proto3,oneof" json:"password,omitempty"`
   Sex      []bool  `protobuf:"varint,4,rep,packed,name=sex,proto3" json:"sex,omitempty"`
}
func (x *User) Reset() {
   *x = User{}
   if protoimpl.UnsafeEnabled {
      mi := &file_user_proto_msgTypes[0]
      ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
      ms.StoreMessageInfo(mi)
   }
}
func (x *User) String() string {
   return protoimpl.X.MessageStringOf(x)
}
func (*User) ProtoMessage() {}
func (x *User) ProtoReflect() protoreflect.Message {
   mi := &file_user_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 User.ProtoReflect.Descriptor instead.
func (*User) Descriptor() ([]byte, []int) {
   return file_user_proto_rawDescGZIP(), []int{0}
}
func (x *User) GetUsername() string {
   if x != nil {
      return x.Username
   }
   return ""
}
func (x *User) GetAge() int32 {
   if x != nil {
      return x.Age
   }
   return 0
}
func (x *User) GetPassword() string {
   if x != nil && x.Password != nil {
      return *x.Password
   }
   return ""
}
func (x *User) GetSex() []bool {
   if x != nil {
      return x.Sex
   }
   return nil
}
var File_user_proto protoreflect.FileDescriptor
var file_user_proto_rawDesc = []byte{
   0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, 0x65,
   0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x74, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a,
   0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
   0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65,
   0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x08, 0x70,
   0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52,
   0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x88, 0x01, 0x01, 0x12, 0x10, 0x0a, 0x03,
   0x73, 0x65, 0x78, 0x18, 0x04, 0x20, 0x03, 0x28, 0x08, 0x52, 0x03, 0x73, 0x65, 0x78, 0x42, 0x0b,
   0x0a, 0x09, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x42, 0x0c, 0x5a, 0x0a, 0x2e,
   0x2e, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
   0x33,
}
var (
   file_user_proto_rawDescOnce sync.Once
   file_user_proto_rawDescData = file_user_proto_rawDesc
)
func file_user_proto_rawDescGZIP() []byte {
   file_user_proto_rawDescOnce.Do(func() {
      file_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_user_proto_rawDescData)
   })
   return file_user_proto_rawDescData
}
var file_user_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_user_proto_goTypes = []interface{}{
   (*User)(nil), // 0: service.User
}
var file_user_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_user_proto_init() }
func file_user_proto_init() {
   if File_user_proto != nil {
      return
   }
   if !protoimpl.UnsafeEnabled {
      file_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
         switch v := v.(*User); i {
         case 0:
            return &v.state
         case 1:
            return &v.sizeCache
         case 2:
            return &v.unknownFields
         default:
            return nil
         }
      }
   }
   file_user_proto_msgTypes[0].OneofWrappers = []interface{}{}
   type x struct{}
   out := protoimpl.TypeBuilder{
      File: protoimpl.DescBuilder{
         GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
         RawDescriptor: file_user_proto_rawDesc,
         NumEnums:      0,
         NumMessages:   1,
         NumExtensions: 0,
         NumServices:   0,
      },
      GoTypes:           file_user_proto_goTypes,
      DependencyIndexes: file_user_proto_depIdxs,
      MessageInfos:      file_user_proto_msgTypes,
   }.Build()
   File_user_proto = out.File
   file_user_proto_rawDesc = nil
   file_user_proto_goTypes = nil
   file_user_proto_depIdxs = nil
}

新建一个main.go文件

package main
import (
  "fmt"
  "google.golang.org/protobuf/proto"
  "protobuf/helloWorld/service"
)
func main() {
  var a = "a"
  user := &service.User{
    Username: "张三",
    Age: 12,
    Sex: []bool{true,true,false},
    Password: &a,
  }
  // 序列化
  marshal, err := proto.Marshal(user)
  if err != nil {
    panic(err)
  }
  fmt.Printf("序列化后:%v\n",marshal)
//  反序列化
  var other = &service.User{}
  err = proto.Unmarshal(marshal, other)
  if err != nil {
    panic(err)
  }
  fmt.Printf("反序列化:%v",user)
}

proto文件字段解释

通常文件名建议命名格式为 包名.消息名.proto

syntax = "proto3";
// 指定使用的proto版本
// option go_package = "path;name";
// path表示生成的go文件存放地址,会自动生成目录
// name 表示生成go文件所属包名
option go_package = "../service";
// 指定文件生成出来的package
package service;

包声明

proto 文件以package声明开头,这有助于防止不同项目之间命名冲突。

字段规则

string username = 1;
  int32 age = 2;
  optional string password = 3;
  repeated bool sex = 4;
  • required:消息体中必填字段,在proto3中默认为该字段。
  • optional: 消息体中可选字段。
  • repeated: 消息体中可重复字段,重复的值的顺序会被保留。其中,proto3默认使用packed方式存储,这样编码方式比较节省内存。

标识号

string username = 1;
  int32 age = 2;
  optional string password = 3;
  repeated bool sex = 4;

在消息体的定义中,每个字段都必须要有一个唯一的标识号,标识号是[0,2^29-1]范围内的一个整数。以上为例username的标识号为1,age标识号为2…

默认值

  • 对于strings,默认是一个空string
  • 对于bytes,默认是一个空bytes
  • 对于bools,默认false
  • 对于数值类型,默认0
  • 对于枚举类型,默认是第一个定义的枚举值,必须为0;
  • 对于消息类型(message),域没有被设置,确切的消息是根据具体语言定义

嵌套

当用于传输和存储较为复杂的信息时,可以将message嵌套写来完成,就比如

message Parents{
  message Child{
    string name = 1;
    int64 age = 2;
  }
}


相关文章
|
17天前
|
Go
Go - 如何编写 ProtoBuf 插件 (一) ?
Go - 如何编写 ProtoBuf 插件 (一) ?
23 2
|
17天前
|
Go
Go - 如何编写 ProtoBuf 插件 (三) ?
Go - 如何编写 ProtoBuf 插件 (三) ?
9 1
|
17天前
|
Go
Go - 如何编写 ProtoBuf 插件(二)?
Go - 如何编写 ProtoBuf 插件(二)?
22 0
|
9月前
|
JSON Linux 测试技术
go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc
go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc
|
缓存 测试技术 Go
使用 go race 排查 protobuf Marshal Panic
使用 go race 排查 protobuf Marshal Panic
142 0
|
存储 XML JSON
Go语言使用protobuf快速入门
protobuf 即 Protocol Buffers,是一种轻便高效的结构化数据存储格式,与语言、平台无关,可扩展可序列化。 protobuf 性能和效率大幅度优于 JSON、XML 等其他的结构化数据格式。 protobuf 是以二进制方式存储的,占用空间小,但也带来了可读性差的缺点。protobuf 在通信协议和数据存储等领域应用广泛。
176 0
|
存储 Java Linux
嵌入式linux之go语言开发(七)protobuf的使用
嵌入式linux之go语言开发(七)protobuf的使用
|
编解码 JSON 安全
Go微服务(二)——Protobuf详细入门 下
Go微服务(二)——Protobuf详细入门 下
236 0
Go微服务(二)——Protobuf详细入门  下
|
存储 编解码 编译器
Go微服务(二)——Protobuf详细入门 中
Go微服务(二)——Protobuf详细入门 中
891 0
Go微服务(二)——Protobuf详细入门   中
|
XML JSON 编解码
Go微服务(二)——Protobuf详细入门 上
Go微服务(二)——Protobuf详细入门 上
200 0
Go微服务(二)——Protobuf详细入门   上