欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

理解Golang组件protobuf

程序员文章站 2022-03-25 16:56:21
什么是protobuf protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。 p ......

什么是protobuf

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 xml,但是比 xml 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

protobuf与json区别

json与protobuf都可以用来信息交换,json是一种简单的消息格式,以文本方式传输,而protobuf是以二进制方式进行传输,相较于json消息体积会有明显的缩小,所以传输速度也比json快。除此之外,protobuf不仅仅是一种用于交换的消息格式,还是用于定义交换消息的规则和工具,目前基本支持所有的主流语言。

使用

先通过命令行进行安装

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

再创建一个名为test.proto的文件,键入以下内容

syntax = "proto3";
package main;

message test {
    string label = 1;
    int32 type = 2;
    repeated int64 reps = 3;
}

我们以proto3为例,创建一个叫test的message,设置三个属性,label、type和int64,repeated对应生成的go语言变量类型为切片。下面在命令行执行protoc来生成go文件。

protoc --go_out=./ test.proto

可以看到在根目录中生成了一个名为test.pb.go的文件

// code generated by protoc-gen-go. do not edit.
// source: test.proto

package main

import (
	fmt "fmt"
	proto "github.com/golang/protobuf/proto"
	math "math"
)

// reference imports to suppress errors if they are not otherwise used.
var _ = proto.marshal
var _ = fmt.errorf
var _ = math.inf

// this is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// a compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.protopackageisversion3 // please upgrade the proto package

type test struct {
	label                string   `protobuf:"bytes,1,opt,name=label,proto3" json:"label,omitempty"`
	type                 int32    `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
	reps                 []int64  `protobuf:"varint,3,rep,packed,name=reps,proto3" json:"reps,omitempty"`
	xxx_nounkeyedliteral struct{} `json:"-"`
	xxx_unrecognized     []byte   `json:"-"`
	xxx_sizecache        int32    `json:"-"`
}

func (m *test) reset()         { *m = test{} }
func (m *test) string() string { return proto.compacttextstring(m) }
func (*test) protomessage()    {}
func (*test) descriptor() ([]byte, []int) {
	return filedescriptor_c161fcfdc0c3ff1e, []int{0}
}

func (m *test) xxx_unmarshal(b []byte) error {
	return xxx_messageinfo_test.unmarshal(m, b)
}
func (m *test) xxx_marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageinfo_test.marshal(b, m, deterministic)
}
func (m *test) xxx_merge(src proto.message) {
	xxx_messageinfo_test.merge(m, src)
}
func (m *test) xxx_size() int {
	return xxx_messageinfo_test.size(m)
}
func (m *test) xxx_discardunknown() {
	xxx_messageinfo_test.discardunknown(m)
}

var xxx_messageinfo_test proto.internalmessageinfo

func (m *test) getlabel() string {
	if m != nil {
		return m.label
	}
	return ""
}

func (m *test) gettype() int32 {
	if m != nil {
		return m.type
	}
	return 0
}

func (m *test) getreps() []int64 {
	if m != nil {
		return m.reps
	}
	return nil
}

func init() {
	proto.registertype((*test)(nil), "main.test")
}

func init() {
	proto.registerfile("test.proto", filedescriptor_c161fcfdc0c3ff1e)
}

var filedescriptor_c161fcfdc0c3ff1e = []byte{
	// 104 bytes of a gzipped filedescriptorproto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0x49, 0x2d, 0x2e,
	0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0xc9, 0x4d, 0xcc, 0xcc, 0x53, 0x72, 0xe1, 0x62,
	0x09, 0x49, 0x2d, 0x2e, 0x11, 0x12, 0xe1, 0x62, 0xcd, 0x49, 0x4c, 0x4a, 0xcd, 0x91, 0x60, 0x54,
	0x60, 0xd4, 0xe0, 0x0c, 0x82, 0x70, 0x84, 0x84, 0xb8, 0x58, 0x4a, 0x2a, 0x0b, 0x52, 0x25, 0x98,
	0x14, 0x18, 0x35, 0x58, 0x83, 0xc0, 0x6c, 0x90, 0x58, 0x51, 0x6a, 0x41, 0xb1, 0x04, 0xb3, 0x02,
	0xb3, 0x06, 0x73, 0x10, 0x98, 0x9d, 0xc4, 0x06, 0x36, 0xd2, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff,
	0x7b, 0xa2, 0xc6, 0x01, 0x60, 0x00, 0x00, 0x00,
}

我们在main文件中进行序列化测试

package main

import (
	"fmt"

	"github.com/golang/protobuf/proto"
)

func main() {
	test := &test{
		label: "a",
		type:  32,
		reps:  []int64{10, 11},
	}
	resp, err := proto.marshal(test)
	if err != nil {
		fmt.println(err)
	}
	fmt.println(resp)
}

protobuf生成了一个名为test的结构体,其中有三个成员属性,正好与test.proto文件对应,执行poroto.marshal方法可以对结构体进行序列化,后续就可以借助rpc或http的载体进行传输。

golang组件示例代码仓库,欢迎star

https://github.com/enochzg/golang-examples