Golang protobuf

什么是protobuf

protobuf也叫protocol buffer是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和 python,每一种实现都包含了相应语言的编译器以及库文件。

由于它是一种二进制的格式,比使用 xml 、json进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。

一、环境的搭建

1.下载protobuf的编译器protoc 
访问https://github.com/google/protobuf/releases 

选自己的版本下载,解压。我用的protoc-3.15.2-linux-x86_64.zip

解压内容放到对应目录下

bin/下的二进制文件放go/bin下

include/下的内容放go/src/github.com下

2.下载protobuf编译器所需插件 
用git下载protoc在go下运行所需插件(执行): go get github.com/golang/protobuf(gopath的bin目录会生成protoc-gen-go.exe), 
此时在gopath的bin目录下你会看到:

二、protobuf的使用

1、新建test.proto文件,protobuf内容如下:

syntax="proto3"; //版本号
package main;  //包名
enum ClassName{   //枚举
    class1=0;  //标号 必须从 0开始
    class2=1;
    class3=2;
}
message Student{ //消息,对应于Go的结构体
  string name=1; //1:标号,唯一 即可(相当于数据库中的Id,不一定要从1 ,2的顺序依次排列。)
  int32 age=2;  //必须指定整型的范围,如int32,int64
  string address=3;
  ClassName cn=4;
}
message Students{
   repeated Student person=1;  // repeated 修饰,相当于Go中切片
   string school=2;
}
 

protobuf类型如下:

2、生成Go文件

生成go文件的命令:protoc --go_out=.   test.proto  (其中: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 ClassName int32
const (
	ClassName_class1 ClassName = 0
	ClassName_class2 ClassName = 1
	ClassName_class3 ClassName = 2
)
var ClassName_name = map[int32]string{
	0: "class1",
	1: "class2",
	2: "class3",
}
var ClassName_value = map[string]int32{
	"class1": 0,
	"class2": 1,
	"class3": 2,
}
func (x ClassName) String() string {
	return proto.EnumName(ClassName_name, int32(x))
}
func (ClassName) EnumDescriptor() ([]byte, []int) {
	return fileDescriptor_c161fcfdc0c3ff1e, []int{0}
}
type Student struct {
	Name                 string    `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
	Age                  int32     `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
	Address              string    `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
	Cn                   ClassName `protobuf:"varint,4,opt,name=cn,proto3,enum=main.ClassName" json:"cn,omitempty"`
	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
	XXX_unrecognized     []byte    `json:"-"`
	XXX_sizecache        int32     `json:"-"`
}
 
func (m *Student) Reset()         { *m = Student{} }
func (m *Student) String() string { return proto.CompactTextString(m) }
func (*Student) ProtoMessage()    {}
func (*Student) Descriptor() ([]byte, []int) {
	return fileDescriptor_c161fcfdc0c3ff1e, []int{0}
}
func (m *Student) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_Student.Unmarshal(m, b)
}
func (m *Student) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_Student.Marshal(b, m, deterministic)
}
func (m *Student) XXX_Merge(src proto.Message) {
	xxx_messageInfo_Student.Merge(m, src)
}
func (m *Student) XXX_Size() int {
	return xxx_messageInfo_Student.Size(m)
}
func (m *Student) XXX_DiscardUnknown() {
	xxx_messageInfo_Student.DiscardUnknown(m)
}
 
var xxx_messageInfo_Student proto.InternalMessageInfo
 
func (m *Student) GetName() string {
	if m != nil {
		return m.Name
	}
	return ""
}
 
func (m *Student) GetAge() int32 {
	if m != nil {
		return m.Age
	}
	return 0
}
 
func (m *Student) GetAddress() string {
	if m != nil {
		return m.Address
	}
	return ""
}
 
func (m *Student) GetCn() ClassName {
	if m != nil {
		return m.Cn
	}
	return ClassName_class1
}
 
type Students struct {
	Person               []*Student `protobuf:"bytes,1,rep,name=person,proto3" json:"person,omitempty"`
	School               string     `protobuf:"bytes,2,opt,name=school,proto3" json:"school,omitempty"`
	XXX_NoUnkeyedLiteral struct{}   `json:"-"`
	XXX_unrecognized     []byte     `json:"-"`
	XXX_sizecache        int32      `json:"-"`
}
 
func (m *Students) Reset()         { *m = Students{} }
func (m *Students) String() string { return proto.CompactTextString(m) }
func (*Students) ProtoMessage()    {}
func (*Students) Descriptor() ([]byte, []int) {
	return fileDescriptor_c161fcfdc0c3ff1e, []int{1}
}
 
func (m *Students) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_Students.Unmarshal(m, b)
}
func (m *Students) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_Students.Marshal(b, m, deterministic)
}
func (m *Students) XXX_Merge(src proto.Message) {
	xxx_messageInfo_Students.Merge(m, src)
}
func (m *Students) XXX_Size() int {
	return xxx_messageInfo_Students.Size(m)
}
func (m *Students) XXX_DiscardUnknown() {
	xxx_messageInfo_Students.DiscardUnknown(m)
}
 
var xxx_messageInfo_Students proto.InternalMessageInfo
 
func (m *Students) GetPerson() []*Student {
	if m != nil {
		return m.Person
	}
	return nil
}
 
func (m *Students) GetSchool() string {
	if m != nil {
		return m.School
	}
	return ""
}
 
func init() {
	proto.RegisterEnum("main.ClassName", ClassName_name, ClassName_value)
	proto.RegisterType((*Student)(nil), "main.Student")
	proto.RegisterType((*Students)(nil), "main.Students")
}
 
func init() { proto.RegisterFile("test.proto", fileDescriptor_c161fcfdc0c3ff1e) }
 
var fileDescriptor_c161fcfdc0c3ff1e = []byte{
	// 204 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x8f, 0xcd, 0x4e, 0xc5, 0x20,
	0x10, 0x85, 0x85, 0x56, 0xae, 0x1d, 0xa3, 0x92, 0x59, 0x18, 0x76, 0x92, 0x9b, 0x98, 0x10, 0x17,
	0x35, 0xf6, 0x3e, 0x82, 0x2b, 0x37, 0x2e, 0xf0, 0x09, 0x90, 0x12, 0x7f, 0xd2, 0x42, 0xd3, 0xc1,
	0xf7, 0x37, 0x45, 0xec, 0xee, 0xfb, 0x72, 0xe0, 0xcc, 0x0c, 0x40, 0x0e, 0x94, 0xfb, 0x65, 0x4d,
	0x39, 0x61, 0x3b, 0xbb, 0xaf, 0x78, 0xfc, 0x86, 0xc3, 0x5b, 0xfe, 0x19, 0x43, 0xcc, 0x88, 0xd0,
	0x46, 0x37, 0x07, 0xc5, 0x34, 0x33, 0x9d, 0x2d, 0x8c, 0x12, 0x1a, 0xf7, 0x11, 0x14, 0xd7, 0xcc,
	0x9c, 0xdb, 0x0d, 0x51, 0xc1, 0xc1, 0x8d, 0xe3, 0x1a, 0x88, 0x54, 0x53, 0x1e, 0xfe, 0x2b, 0xde,
	0x01, 0xf7, 0x51, 0xb5, 0x9a, 0x99, 0xeb, 0xe1, 0xa6, 0xdf, 0xda, 0xfb, 0xe7, 0xc9, 0x11, 0xbd,
	0xba, 0x39, 0x58, 0xee, 0xe3, 0xf1, 0x05, 0x2e, 0xea, 0x2c, 0xc2, 0x7b, 0x10, 0x4b, 0x58, 0x29,
	0x45, 0xc5, 0x74, 0x63, 0x2e, 0x87, 0xab, 0xbf, 0x0f, 0x35, 0xb7, 0x35, 0xc4, 0x5b, 0x10, 0xe4,
	0x3f, 0x53, 0x9a, 0xca, 0x0a, 0x9d, 0xad, 0xf6, 0xf0, 0x08, 0xdd, 0xde, 0x8d, 0x00, 0xc2, 0x6f,
	0xf2, 0x24, 0xcf, 0x76, 0x1e, 0x24, 0xdb, 0xf9, 0x24, 0xf9, 0xbb, 0x28, 0x47, 0x9f, 0x7e, 0x03,
	0x00, 0x00, 0xff, 0xff, 0x67, 0x97, 0x87, 0x75, 0x02, 0x01, 0x00, 0x00,
}

可以看成,将protobuf message对应的内容生成结构体,通过GetXX方法来获取对应的值。

3、Golang的使用

package main
 
import (
	"fmt"
	"github.com/golang/protobuf/proto"
)
 
func main() {
	s1:=&Student{} //第一个学生信息
	s1.Name="jz01"
	s1.Age=23
	s1.Address="cq"
	s1.Cn=ClassName_class2 //枚举类型赋值
	ss:=&Students{}
	ss.Person=append(ss.Person,s1) //将第一个学生信息添加到Students对应的切片中
	s2:=&Student{}  //第二个学生信息
	s2.Name="jz02"
	s2.Age=25
	s2.Address="cd"
	s2.Cn=ClassName_class3
	ss.Person=append(ss.Person,s2)//将第二个学生信息添加到Students对应的切片中
	ss.School="cqu"
	fmt.Println("Students信息为:",ss)
 
	// Marshal takes a protocol buffer message
	// and encodes it into the wire format, returning the data.
	buffer, _ := proto.Marshal(ss)
	fmt.Println("序列化之后的信息为:",buffer)
	// 	Use UnmarshalMerge to preserve and append to existing data.
	data:=&Students{}
	proto.Unmarshal(buffer,data)
	fmt.Println("反序列化之后的信息为:",data)
}

注:序列化以后数据被转换成二进制类型(即适合于网络传输的protobuf类型,也就是将结构体类型转换为protobuf类型),反序列化后直接写入(转换)对应的结构体类型(也就是将protobuf类型转换为对应的结构体类型)。 

 

➢了解更多Go语言知识:https://study.163.com/course/introduction/1210620804.htm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值