protobuf是一个跨语言的传输协议格式,其功能和json相似. protobuf和json不一样的是proto使用二进制进行传输,速度上会比json效率高. 可是在可读性上比json差.javascript
protobuf底层使用C++实现的.但如今已经支持不少的语言使用了.目前支持:C++,java,python,objective-c,c#, javascript, ruby, go, php, Dart. 在这里讲protobuf在go中的使用.我使用的环境是ubuntu 16.04php
在使用以前须要安装proto的基础包.基础包是C++编写的,因此须要用到编译C++一些常规的环境,这里不具体介绍.java
安装go的环境python
再者获取go相关的插件包:go get -u github.com/golang/protobuf
git
获取以后进入相应的文件夹,使用go build
, go install
进行编译和安装.使用命令:proto --version
测试是否成功安装.github
chenmei@bogon:~/go/src/test/protobuf$ protoc --version libprotoc 2.6.1
下面咱们就看一个使用的例子,先写一个proto的原文件,这里以学生以及和学生管理的考试成绩为例子:golang
syntax = "proto2"; package pb; message Course { required string name = 1; required int32 score = 2; } message Student { required int32 UUID = 1; required string Username = 2; repeated Course courses = 3; } message Studentlist { repeated Student students = 1; }
上面就定义了课程,学生,以及学生的列表这几个结构.objective-c
使用命令进行转换:json
protoc --go_out=. Studentlist.proto
当转换完成会生成以下的文件:ubuntu
// Code generated by protoc-gen-go. DO NOT EDIT. // source: Studentlist.proto package pb 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 Course struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Score *int32 `protobuf:"varint,2,req,name=score" json:"score,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *Course) Reset() { *m = Course{} } func (m *Course) String() string { return proto.CompactTextString(m) } func (*Course) ProtoMessage() {} func (*Course) Descriptor() ([]byte, []int) { return fileDescriptor_14fc7c21f335a148, []int{0} } func (m *Course) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Course.Unmarshal(m, b) } func (m *Course) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Course.Marshal(b, m, deterministic) } func (m *Course) XXX_Merge(src proto.Message) { xxx_messageInfo_Course.Merge(m, src) } func (m *Course) XXX_Size() int { return xxx_messageInfo_Course.Size(m) } func (m *Course) XXX_DiscardUnknown() { xxx_messageInfo_Course.DiscardUnknown(m) } var xxx_messageInfo_Course proto.InternalMessageInfo func (m *Course) GetName() string { if m != nil && m.Name != nil { return *m.Name } return "" } func (m *Course) GetScore() int32 { if m != nil && m.Score != nil { return *m.Score } return 0 } type Student struct { UUID *int32 `protobuf:"varint,1,req,name=UUID" json:"UUID,omitempty"` Username *string `protobuf:"bytes,2,req,name=Username" json:"Username,omitempty"` Courses []*Course `protobuf:"bytes,3,rep,name=courses" json:"courses,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_14fc7c21f335a148, []int{1} } 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) GetUUID() int32 { if m != nil && m.UUID != nil { return *m.UUID } return 0 } func (m *Student) GetUsername() string { if m != nil && m.Username != nil { return *m.Username } return "" } func (m *Student) GetCourses() []*Course { if m != nil { return m.Courses } return nil } type Studentlist struct { Students []*Student `protobuf:"bytes,1,rep,name=students" json:"students,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *Studentlist) Reset() { *m = Studentlist{} } func (m *Studentlist) String() string { return proto.CompactTextString(m) } func (*Studentlist) ProtoMessage() {} func (*Studentlist) Descriptor() ([]byte, []int) { return fileDescriptor_14fc7c21f335a148, []int{2} } func (m *Studentlist) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Studentlist.Unmarshal(m, b) } func (m *Studentlist) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Studentlist.Marshal(b, m, deterministic) } func (m *Studentlist) XXX_Merge(src proto.Message) { xxx_messageInfo_Studentlist.Merge(m, src) } func (m *Studentlist) XXX_Size() int { return xxx_messageInfo_Studentlist.Size(m) } func (m *Studentlist) XXX_DiscardUnknown() { xxx_messageInfo_Studentlist.DiscardUnknown(m) } var xxx_messageInfo_Studentlist proto.InternalMessageInfo func (m *Studentlist) GetStudents() []*Student { if m != nil { return m.Students } return nil } func init() { proto.RegisterType((*Course)(nil), "pb.Course") proto.RegisterType((*Student)(nil), "pb.Student") proto.RegisterType((*Studentlist)(nil), "pb.Studentlist") } func init() { proto.RegisterFile("Studentlist.proto", fileDescriptor_14fc7c21f335a148) } var fileDescriptor_14fc7c21f335a148 = []byte{ // 158 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x0c, 0x2e, 0x29, 0x4d, 0x49, 0xcd, 0x2b, 0xc9, 0xc9, 0x2c, 0x2e, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2a, 0x48, 0x52, 0x52, 0xe5, 0x62, 0x73, 0xce, 0x2f, 0x2d, 0x2a, 0x4e, 0x15, 0xe2, 0xe1, 0x62, 0xc9, 0x4b, 0xcc, 0x4d, 0x95, 0x60, 0x54, 0x60, 0xd2, 0xe0, 0x14, 0xe2, 0xe5, 0x62, 0x2d, 0x4e, 0xce, 0x2f, 0x4a, 0x95, 0x60, 0x52, 0x60, 0xd2, 0x60, 0x55, 0x72, 0xe3, 0x62, 0x87, 0xea, 0x07, 0xa9, 0x0b, 0x0d, 0xf5, 0x74, 0x01, 0xab, 0x63, 0x15, 0x12, 0xe0, 0xe2, 0x08, 0x2d, 0x4e, 0x2d, 0x02, 0xeb, 0x64, 0x02, 0xeb, 0x94, 0xe6, 0x62, 0x4f, 0x06, 0x9b, 0x58, 0x2c, 0xc1, 0xac, 0xc0, 0xac, 0xc1, 0x6d, 0xc4, 0xa5, 0x57, 0x90, 0xa4, 0x07, 0xb1, 0x44, 0x49, 0x87, 0x8b, 0x1b, 0xc9, 0x1d, 0x42, 0xb2, 0x5c, 0x1c, 0xc5, 0x10, 0x6e, 0xb1, 0x04, 0x23, 0x58, 0x31, 0x37, 0x48, 0x31, 0x54, 0x09, 0x20, 0x00, 0x00, 0xff, 0xff, 0x66, 0x6d, 0x7d, 0x4c, 0xb4, 0x00, 0x00, 0x00, }
下面看main.go的写法,在main里面先对数据进行序列化,而后再反序列化.
package main import ( "fmt" "test/protobuf/pb" "github.com/golang/protobuf/proto" ) func main() { course11 := pb.Course{ Name: proto.String("math"), Score: proto.Int32(99), } course12 := pb.Course { Name: proto.String("english"), Score: proto.Int32(90), } course21 := pb.Course{ Name: proto.String("math"), Score: proto.Int32(94), } course22 := pb.Course { Name: proto.String("english"), Score: proto.Int32(95), } student1 := pb.Student { UUID: proto.Int32(1), Username: proto.String("mei.chen"), Courses: []*pb.Course{&course11, &course12}, } student2 := pb.Student { UUID: proto.Int32(2), Username: proto.String("he.he"), Courses: []*pb.Course{&course21, &course22}, } students := pb.Studentlist { Students: []*pb.Student{&student1,&student2}, } //序列化: data, err := proto.Marshal(&students) if err != nil { fmt.Println("marshal error", err) } fmt.Println("marshal data:",data) //反序列化 var list pb.Studentlist err = proto.Unmarshal(data, &list) if err != nil { fmt.Println("unmarshal error:",err) } for _, student := range list.Students { fmt.Println("------------------------------------------") fmt.Println("sudent name: ",student.GetUsername()) for _, course := range student.Courses { fmt.Println("course: ",course.GetName()) fmt.Println("score: ",course.GetScore()) } } }
输出结果以下:
marshal data: [10 35 8 1 18 8 109 101 105 46 99 104 101 110 26 8 10 4 109 97 116 104 16 99 26 11 10 7 101 110 103 108 105 115 104 16 90 10 32 8 2 18 5 104 101 46 104 101 26 8 10 4 109 97 116 104 16 94 26 11 10 7 101 110 103 108 105 115 104 16 95] ------------------------------------------ sudent name: mei.chen course: math score: 99 course: english score: 90 ------------------------------------------ sudent name: he.he course: math score: 94 course: english score: 95
这里须要注意的地方:
1.在proto文件中定义的字段若是首字母是小写,那么在转换的时候会变成大写.
2.在proto中定义的类型其实都是指针,例如string,须要使用proto.String转为指针类型. 这个你能够在转换后的文件中能够看到.
做者:amei 连接:http://114.116.145.166:5897/blogs/amei/articles/2019/04/02/1554195518207