protobuf介绍

系列文章目录

在这里插入图片描述

前言

Protocol Buffers(简称Protobuf)是一种轻量级、高效的数据交换格式,它是由Google开发的,用于在不同系统之间进行数据通信、存储和序列化的协议。
在这里插入图片描述

一、Protocol Buffers是什么?

数据序列化格式:Protobuf 是一种二进制数据序列化格式,用于将结构化数据转换为字节流,以便于存储、传输和恢复。

语言无关:Protobuf 不与任何特定编程语言相关,因此可以使用多种编程语言来编写生成和解析 Protobuf 格式的数据。

高效:Protobuf 数据相对于其他文本格式(如XML和JSON)非常紧凑,序列化和反序列化速度非常快。

可扩展性:Protobuf 支持向已定义的消息类型添加新字段,而不会破坏现有的代码,这使得协议的演化变得相对容易。

IDL(Interface Description Language):Protobuf 使用一种IDL来定义消息结构,它是一种描述消息格式的语言,通常包括消息的字段、类型和其他元数据。然后,通过IDL编译器,可以生成用于不同编程语言的消息类。

消息结构:Protobuf 消息由一系列字段组成,每个字段都有一个唯一的标识符和一个数据类型。支持的数据类型包括整数、浮点数、字符串、枚举、子消息等。

版本兼容性:Protobuf 支持消息结构的演化,可以向已存在的消息添加新字段,删除字段,或者更改字段的类型,而不会影响已存在的代码。

跨平台兼容性:由于Protobuf生成的数据是二进制的,它可以在不同操作系统和编程语言之间轻松传输和解析。

代码生成:通常,Protobuf 编译器会将IDL文件编译成各种编程语言的源代码文件,以便开发人员可以使用生成的代码来序列化、反序列化和操作消息。
protobuf的优劣势
1)优势:

序列化后体积相比Json和XML很小,适合网络传输

序列化反序列化速度很快,快于Json的处理速度

消息格式升级和兼容性还不错

支持跨平台多语言

2)劣势:

应用不够广(相比xml和json)

二进制格式导致可读性差

缺乏自描述

protoc安装(windows)
protoc就是protobuf的编译器,它把proto文件编译成不同的语言

下载安装protoc编译器(protoc)
下载protobuf:https://github.com/protocolbuffers/protobuf/releases/download/v3.20.1/protoc-3.20.1-win64.zip
安装protocbuf的go插件(protoc-gen-go)
由于protobuf并没直接支持go语言需要我们手动安装相关插件

protocol buffer编译器需要一个插件来根据提供的proto文件生成 Go 代码,Go1.16+要使用下面的命令安装插件:

 go install google.golang.org/protobuf/cmd/protoc-gen-go@latest  // 目前最新版是v1.3.0

解压后,将目录中的 bin 目录的路径添加到系统环境变量,然后打开cmd输入protoc查看输出信息,此时则安装成功

简单语法
proto文件基本语法
 syntax = "proto3";              // 指定版本信息,不指定会报错
 package pb;                     // 后期生成go文件的包名
 // message为关键字,作用为定义一种消息类型
 message Person{
     string name = 1;   // 名字
     int32  age = 2 ;   // 年龄
 }
 ​
 enum test{
     int32 age = 0;
 }

三、使用示例

在Go中使用Protocol Buffers(protobuf)可以帮助你定义和序列化结构化数据。首先,你需要安装 protoc 编译器和 Go 的 Protocol Buffers 插件。然后,你可以按照以下步骤创建一个简单的示例。

  1. 安装 protoc 编译器和 Go 插件:

    # 安装 protoc 编译器
    brew install protobuf
    
    # 安装 Go 的 Protocol Buffers 插件
    go get -u github.com/golang/protobuf/protoc-gen-go
    
  2. 创建一个 .proto 文件来定义消息:

    例如,创建一个名为 person.proto 的文件:

    syntax = "proto3";
    
    package main;
    
    message Person {
      string name = 1;
      int32 age = 2;
    }
    
  3. 使用 protoc 编译器生成 Go 代码:

    protoc --go_out=. person.proto
    

    这将生成一个名为 person.pb.go 的 Go 文件。

  4. 创建一个 Go 程序来使用 Protocol Buffers 消息:

    package main
    
    import (
        "fmt"
        "log"
        "github.com/golang/protobuf/proto"
    )
    
    func main() {
        person := &Person{
            Name: "Alice",
            Age: 30,
        }
    
        // 序列化
        data, err := proto.Marshal(person)
        if err != nil {
            log.Fatal("marshaling error: ", err)
        }
    
        // 反序列化
        newPerson := &Person{}
        err = proto.Unmarshal(data, newPerson)
        if err != nil {
            log.Fatal("unmarshaling error: ", err)
        }
    
        // 打印数据
        fmt.Printf("Original Person: %v\n", person)
        fmt.Printf("Unmarshaled Person: %v\n", newPerson)
    }
    

    请确保在你的代码中导入正确的包,例如 import "github.com/golang/protobuf/proto"import "your_package_name",然后你就可以使用 Protocol Buffers 来序列化和反序列化数据。

确保你的 Go 工作环境已经设置好,并且你已经替换 your_package_name 为你的实际包名称。这个示例演示了如何定义一个简单的消息类型,序列化和反序列化数据。你可以按照类似的模式来定义更复杂的消息类型和应用程序。

四、生成go文件

为什么要安装protoc和protoc-gen-go
在使用 Protocol Buffers(protobuf)时,protoc 是 Protocol Buffers 编译器,而 protoc-gen-go 是用于生成 Go 语言代码的插件。您需要安装它们的原因如下:

  1. 编译 protobuf 文件: protoc 编译器用于将您的 .proto 文件编译为不同编程语言的代码。它将 .proto 文件转换为可在各种编程语言中使用的数据结构和序列化/反序列化代码。

  2. 生成 Go 语言代码: protoc-gen-go 插件是针对 Go 语言的插件,它扩展了 protoc 编译器,以便生成 Go 语言代码。这包括生成消息结构、序列化和反序列化函数等,使您可以在 Go 项目中使用 Protocol Buffers 数据。

具体来说,protoc-gen-go 插件生成了以下内容:

  • Go 结构体:它将 .proto 文件中的消息定义转换为 Go 语言中的结构体,使您可以在 Go 代码中使用这些消息类型。

  • 序列化和反序列化函数:生成的 Go 代码包括用于将消息序列化为二进制数据和将二进制数据反序列化为消息的函数。

  • 其他辅助函数:它还生成了用于检查消息的有效性和创建默认消息实例等辅助函数。

  • gRPC 代码(如果包含 gRPC 服务定义):如果您的 .proto 文件还包含 gRPC 服务定义,protoc-gen-go 会生成用于实现和调用 gRPC 服务的代码。

因此,安装 protocprotoc-gen-go 是为了将您的 Protocol Buffers 文件编译为 Go 语言代码,以便您可以在 Go 项目中使用 Protocol Buffers 数据和 gRPC 服务。这种结合使用可以提供跨语言数据交换和 RPC 通信的强大功能,同时保持了类型安全和高效的序列化。

要使用 Protocol Buffers (protobuf) 生成 Go 语言代码,您需要使用 protoc 编译器以及相应的插件。以下是一些生成 Go 代码的命令:

  1. 首先,确保您已经安装了 Protocol Buffers 编译器 protoc。如果您还没有安装,可以从 https://github.com/protocolbuffers/protobuf/releases 下载并安装它。

  2. 安装 Go 的 Protocol Buffers 插件。您可以使用以下命令安装 protoc-gen-go 插件:

    go install google.golang.org/protobuf/cmd/protoc-gen-go
    

    如果您使用的是旧版本的 Go,您可以尝试以下命令:

    go get -u github.com/golang/protobuf/protoc-gen-go
    
  3. 编写您的 Protocol Buffers 定义文件(通常以 .proto 为扩展名),定义您的消息类型和服务等。

  4. 使用 protoc 编译器生成 Go 代码。以下是一些常用的命令示例:

    protoc --go_out=. yourfile.proto
    

    这将生成一个 yourfile.pb.go 文件,其中包含您在 .proto 文件中定义的消息的 Go 代码。

    如果您的 .proto 文件包含 gRPC 服务定义,您还需要生成 gRPC 相关的代码。可以使用以下命令:

    protoc --go-grpc_out=. yourfile.proto
    

    这将生成一个 yourfile_grpc.pb.go 文件,其中包含 gRPC 相关的 Go 代码。

请替换 yourfile.proto 为您的实际 .proto 文件的名称。这些命令将生成与您的 Protocol Buffers 文件相对应的 Go 代码,以便您可以在 Go 中使用它们。确保在运行这些命令之前,您的 .proto 文件位于合适的目录,并且您已经安装了所需的 Go 插件。
示例:
proto源文件

syntax = "proto3";

message HelloRequest {
  string name =1;//1 是编号
  int32  age =2;
}

生成之后的go文件

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.30.0
// 	protoc        v4.23.0
// source: hello.proto

package __

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 HelloRequest struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` //1 是编号
	Age  int32  `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
}

func (x *HelloRequest) Reset() {
	*x = HelloRequest{}
	if protoimpl.UnsafeEnabled {
		mi := &file_hello_proto_msgTypes[0]
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
		ms.StoreMessageInfo(mi)
	}
}

func (x *HelloRequest) String() string {
	return protoimpl.X.MessageStringOf(x)
}

func (*HelloRequest) ProtoMessage() {}

func (x *HelloRequest) ProtoReflect() protoreflect.Message {
	mi := &file_hello_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 HelloRequest.ProtoReflect.Descriptor instead.
func (*HelloRequest) Descriptor() ([]byte, []int) {
	return file_hello_proto_rawDescGZIP(), []int{0}
}

func (x *HelloRequest) GetName() string {
	if x != nil {
		return x.Name
	}
	return ""
}

func (x *HelloRequest) GetAge() int32 {
	if x != nil {
		return x.Age
	}
	return 0
}

var File_hello_proto protoreflect.FileDescriptor

var file_hello_proto_rawDesc = []byte{
	0x0a, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70,
	0x72, 0x6f, 0x74, 0x6f, 0x22, 0x34, 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71,
	0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
	0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18,
	0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x42, 0x04, 0x5a, 0x02, 0x2e, 0x2f,
	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
	file_hello_proto_rawDescOnce sync.Once
	file_hello_proto_rawDescData = file_hello_proto_rawDesc
)

func file_hello_proto_rawDescGZIP() []byte {
	file_hello_proto_rawDescOnce.Do(func() {
		file_hello_proto_rawDescData = protoimpl.X.CompressGZIP(file_hello_proto_rawDescData)
	})
	return file_hello_proto_rawDescData
}

var file_hello_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_hello_proto_goTypes = []interface{}{
	(*HelloRequest)(nil), // 0: proto.HelloRequest
}
var file_hello_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_hello_proto_init() }
func file_hello_proto_init() {
	if File_hello_proto != nil {
		return
	}
	if !protoimpl.UnsafeEnabled {
		file_hello_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
			switch v := v.(*HelloRequest); 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_hello_proto_rawDesc,
			NumEnums:      0,
			NumMessages:   1,
			NumExtensions: 0,
			NumServices:   0,
		},
		GoTypes:           file_hello_proto_goTypes,
		DependencyIndexes: file_hello_proto_depIdxs,
		MessageInfos:      file_hello_proto_msgTypes,
	}.Build()
	File_hello_proto = out.File
	file_hello_proto_rawDesc = nil
	file_hello_proto_goTypes = nil
	file_hello_proto_depIdxs = nil
}

五、go的proto文件编解码

在 Go 中,proto.Marshal 函数是 Protocol Buffers(protobuf)库的一部分,用于将 protobuf 消息结构序列化为二进制数据。这是在将 protobuf 消息传输或存储时非常有用的功能,因为它允许您将消息转换为紧凑的二进制表示,以便进行传输或持久化。

以下是有关 proto.Marshal 的介绍:

  1. 函数签名:

    func Marshal(pb Message) ([]byte, error)
    
    • pb:需要序列化的 Protocol Buffers 消息对象,它必须实现 proto.Message 接口。
    • 返回值:一个字节数组([]byte)表示序列化后的消息。
    • 错误:如果序列化失败,将返回一个非空的错误。
  2. 使用示例:

    // 导入必要的包
    import (
        "github.com/golang/protobuf/proto"
        "your_package/your_proto_file"
    )
    
    func main() {
        // 创建一个 Protocol Buffers 消息对象
        msg := &your_proto_file.YourMessage{
            Field1: "Hello",
            Field2: 42,
        }
    
        // 使用 proto.Marshal 进行序列化
        data, err := proto.Marshal(msg)
        if err != nil {
            // 处理错误
            log.Fatalf("Failed to marshal: %v", err)
        }
    
        // 现在,'data' 包含序列化后的二进制数据
        // 您可以将它发送到网络、存储到文件或以其他方式使用它
    }
    

proto.Marshal 将消息对象序列化为 Protocol Buffers 格式,使其易于传输和存储。这个函数是 Protocol Buffers 库的一部分,因此您需要导入 github.com/golang/protobuf/proto 包,以及您自己的 Protocol Buffers 消息定义的包。

另外,要注意处理潜在的错误,因为 proto.Marshal 可能返回一个错误,例如当消息无法正确序列化时。通常,您应该在使用 proto.Marshal 时包含错误检查,并根据需要进行错误处理。

五、protobuf的go对应类型

Protocol Buffers (protobuf) 是一种数据序列化格式,而 Go 是一种编程语言。在 Go 中,你可以使用 Protocol Buffers 来定义数据结构,然后使用 protoc 编译器生成 Go 代码来操作这些数据结构。下面是 Protocol Buffers 中的类型和它们在 Go 中的对应关系:

  1. doublefloat

    • Protocol Buffers: double, float
    • Go: float64, float32
  2. int32, int64, uint32, uint64, sint32, sint64, fixed32, fixed64, sfixed32, sfixed64

    • Protocol Buffers: 整数类型
    • Go: int32, int64, uint32, uint64, int32, int64, uint32, uint64, int32, int64
  3. bool

    • Protocol Buffers: bool
    • Go: bool
  4. string

    • Protocol Buffers: string
    • Go: string
  5. bytes

    • Protocol Buffers: bytes
    • Go: []byte
  6. enum

    • Protocol Buffers: 枚举类型
    • Go: int32
  7. message

    • Protocol Buffers: 消息类型
    • Go: 生成的 Go 结构体,具有相应的字段和方法
  8. repeated(重复字段)

    • Protocol Buffers: repeated 关键字用于表示重复字段
    • Go: 切片(Slice)用于存储重复字段的数据

这些是一些常见的类型对应关系,但 Protocol Buffers 支持更多的类型和选项。当你在 Protocol Buffers 中定义消息时,protoc 编译器会生成相应的 Go 结构体以及用于序列化和反序列化的方法。你可以使用生成的 Go 代码来操作 Protocol Buffers 数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值