go protobuf
go protobuf
安装protoc工具
protoc工具用来将.proto文件转化为自己使用的语言格式。
首先去https://github.com/protocolbuffers/protobuf/releases下载protobuf的编译器protoc,windows上可以直接下到exe文件(linux则需要编译),最后将下载好的可执行文件拷贝到$GOPATH的bin目录下($GOPATH/bin目录最好添加到系统环境变量里)
linux环境,下载protoc源码,下载地址,我选择如图的安装包,可以不需要再编译,直接将bin添加到环境变量中或者将bin/protoc 软链接到/usr/bin下。
protobuf插件
go语言相关的有两个插件gogoprotobuf和goprotobuf(官方出品)
我这块选择gogoprotobuf(比官方感觉更好),同样也兼容官方
go get github.com/gogo/protobuf/protoc-gen-gofast
编写test.proto文件
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; }
根据test.proto自动生成go源码test.pb.go
protoc --gofast_out=.\ .\test.proto
// Code generated by protoc-gen-gogo. DO NOT EDIT. // source: test.proto package main import ( fmt "fmt" proto "github.com/gogo/protobuf/proto" io "io" math "math" math_bits "math/bits" ) // 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 // 注释掉此行,否则编译报错 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 m.Unmarshal(b) } func (m *Student) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_Student.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } return b[:n], nil } } func (m *Student) XXX_Merge(src proto.Message) { xxx_messageInfo_Student.Merge(m, src) } func (m *Student) XXX_Size() int { return m.Size() } 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 m.Unmarshal(b) } func (m *Students) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_Students.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } return b[:n], nil } } func (m *Students) XXX_Merge(src proto.Message) { xxx_messageInfo_Students.Merge(m, src) } func (m *Students) XXX_Size() int { return m.Size() } 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{ // 230 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x90, 0x3d, 0x4e, 0xc4, 0x30, 0x10, 0x85, 0x77, 0x92, 0x90, 0x25, 0x83, 0x00, 0x6b, 0x0a, 0xe4, 0x2a, 0x44, 0x2b, 0x21, 0x45, 0x14, 0x41, 0x64, 0x6f, 0x00, 0x15, 0x0d, 0x85, 0x39, 0x81, 0x49, 0x2c, 0x7e, 0xb4, 0xb1, 0x57, 0x19, 0x73, 0x17, 0x8e, 0x44, 0xc9, 0x11, 0x50, 0xb8, 0x08, 0x8a, 0xf1, 0xa6, 0xfb, 0x3e, 0x3d, 0xfb, 0xcd, 0x68, 0x10, 0xbd, 0x61, 0xdf, 0xec, 0x47, 0xe7, 0x1d, 0x65, 0x83, 0x7e, 0xb3, 0x9b, 0x77, 0x5c, 0x3f, 0xf9, 0x8f, 0xde, 0x58, 0x4f, 0x84, 0x99, 0xd5, 0x83, 0x91, 0x50, 0x41, 0x5d, 0xa8, 0xc0, 0x24, 0x30, 0xd5, 0x2f, 0x46, 0x26, 0x15, 0xd4, 0x47, 0x6a, 0x46, 0x92, 0xb8, 0xd6, 0x7d, 0x3f, 0x1a, 0x66, 0x99, 0x86, 0x87, 0x07, 0xa5, 0x4b, 0x4c, 0x3a, 0x2b, 0xb3, 0x0a, 0xea, 0xb3, 0xf6, 0xbc, 0x99, 0xdb, 0x9b, 0xfb, 0x9d, 0x66, 0x7e, 0xd4, 0x83, 0x51, 0x49, 0x67, 0x37, 0x0f, 0x78, 0x1c, 0x67, 0x31, 0x5d, 0x61, 0xbe, 0x37, 0x23, 0x3b, 0x2b, 0xa1, 0x4a, 0xeb, 0x93, 0xf6, 0xf4, 0xff, 0x43, 0xcc, 0x55, 0x0c, 0xe9, 0x02, 0x73, 0xee, 0x5e, 0x9d, 0xdb, 0x85, 0x15, 0x0a, 0x15, 0xed, 0xfa, 0x06, 0x8b, 0xa5, 0x9b, 0x10, 0xf3, 0x6e, 0x96, 0x5b, 0xb1, 0x5a, 0xb8, 0x15, 0xb0, 0xf0, 0x56, 0x24, 0x77, 0xe2, 0x6b, 0x2a, 0xe1, 0x7b, 0x2a, 0xe1, 0x67, 0x2a, 0xe1, 0xf3, 0xb7, 0x5c, 0x3d, 0xe7, 0xe1, 0x0c, 0xdb, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0xbf, 0xc4, 0x8f, 0x14, 0x01, 0x00, 0x00, } func (m *Student) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil } func (m *Student) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } func (m *Student) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l if m.XXX_unrecognized != nil { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } if m.Cn != 0 { i = encodeVarintTest(dAtA, i, uint64(m.Cn)) i-- dAtA[i] = 0x20 } if len(m.Address) > 0 { i -= len(m.Address) copy(dAtA[i:], m.Address) i = encodeVarintTest(dAtA, i, uint64(len(m.Address))) i-- dAtA[i] = 0x1a } if m.Age != 0 { i = encodeVarintTest(dAtA, i, uint64(m.Age)) i-- dAtA[i] = 0x10 } if len(m.Name) > 0 { i -= len(m.Name) copy(dAtA[i:], m.Name) i = encodeVarintTest(dAtA, i, uint64(len(m.Name))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } func (m *Students) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil } func (m *Students) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } func (m *Students) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l if m.XXX_unrecognized != nil { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } if len(m.School) > 0 { i -= len(m.School) copy(dAtA[i:], m.School) i = encodeVarintTest(dAtA, i, uint64(len(m.School))) i-- dAtA[i] = 0x12 } if len(m.Person) > 0 { for iNdEx := len(m.Person) - 1; iNdEx >= 0; iNdEx-- { { size, err := m.Person[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } i -= size i = encodeVarintTest(dAtA, i, uint64(size)) } i-- dAtA[i] = 0xa } } return len(dAtA) - i, nil } func encodeVarintTest(dAtA []byte, offset int, v uint64) int { offset -= sovTest(v) base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) return base } func (m *Student) Size() (n int) { if m == nil { return 0 } var l int _ = l l = len(m.Name) if l > 0 { n += 1 + l + sovTest(uint64(l)) } if m.Age != 0 { n += 1 + sovTest(uint64(m.Age)) } l = len(m.Address) if l > 0 { n += 1 + l + sovTest(uint64(l)) } if m.Cn != 0 { n += 1 + sovTest(uint64(m.Cn)) } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } func (m *Students) Size() (n int) { if m == nil { return 0 } var l int _ = l if len(m.Person) > 0 { for _, e := range m.Person { l = e.Size() n += 1 + l + sovTest(uint64(l)) } } l = len(m.School) if l > 0 { n += 1 + l + sovTest(uint64(l)) } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } func sovTest(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } func sozTest(x uint64) (n int) { return sovTest(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } func (m *Student) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTest } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= uint64(b&0x7F) << shift if b < 0x80 { break } } fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { return fmt.Errorf("proto: Student: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: Student: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTest } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } intStringLen := int(stringLen) if intStringLen < 0 { return ErrInvalidLengthTest } postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTest } if postIndex > l { return io.ErrUnexpectedEOF } m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field Age", wireType) } m.Age = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTest } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ m.Age |= int32(b&0x7F) << shift if b < 0x80 { break } } case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTest } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } intStringLen := int(stringLen) if intStringLen < 0 { return ErrInvalidLengthTest } postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTest } if postIndex > l { return io.ErrUnexpectedEOF } m.Address = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field Cn", wireType) } m.Cn = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTest } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ m.Cn |= ClassName(b&0x7F) << shift if b < 0x80 { break } } default: iNdEx = preIndex skippy, err := skipTest(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTest } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } if iNdEx > l { return io.ErrUnexpectedEOF } return nil } func (m *Students) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTest } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= uint64(b&0x7F) << shift if b < 0x80 { break } } fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { return fmt.Errorf("proto: Students: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: Students: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Person", wireType) } var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTest } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ msglen |= int(b&0x7F) << shift if b < 0x80 { break } } if msglen < 0 { return ErrInvalidLengthTest } postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTest } if postIndex > l { return io.ErrUnexpectedEOF } m.Person = append(m.Person, &Student{}) if err := m.Person[len(m.Person)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field School", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTest } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } intStringLen := int(stringLen) if intStringLen < 0 { return ErrInvalidLengthTest } postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTest } if postIndex > l { return io.ErrUnexpectedEOF } m.School = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTest(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTest } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } if iNdEx > l { return io.ErrUnexpectedEOF } return nil } func skipTest(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return 0, ErrIntOverflowTest } if iNdEx >= l { return 0, io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } } wireType := int(wire & 0x7) switch wireType { case 0: for shift := uint(0); ; shift += 7 { if shift >= 64 { return 0, ErrIntOverflowTest } if iNdEx >= l { return 0, io.ErrUnexpectedEOF } iNdEx++ if dAtA[iNdEx-1] < 0x80 { break } } case 1: iNdEx += 8 case 2: var length int for shift := uint(0); ; shift += 7 { if shift >= 64 { return 0, ErrIntOverflowTest } if iNdEx >= l { return 0, io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ length |= (int(b) & 0x7F) << shift if b < 0x80 { break } } if length < 0 { return 0, ErrInvalidLengthTest } iNdEx += length case 3: depth++ case 4: if depth == 0 { return 0, ErrUnexpectedEndOfGroupTest } depth-- case 5: iNdEx += 4 default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } if iNdEx < 0 { return 0, ErrInvalidLengthTest } if depth == 0 { return iNdEx, nil } } return 0, io.ErrUnexpectedEOF } var ( ErrInvalidLengthTest = fmt.Errorf("proto: negative length found during unmarshaling") ErrIntOverflowTest = fmt.Errorf("proto: integer overflow") ErrUnexpectedEndOfGroupTest = fmt.Errorf("proto: unexpected end of group") )
可以看成,将protobuf message对应的内容生成结构体,通过GetXX方法来获取对应的值。
Golang的使用
package main
import (
"fmt"
"github.com/gogo/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)
for i := 0; i < len(ss.Person); i++ {
s11 := ss.Person[i]
fmt.Println(s11)
}
}
注:序列化以后数据被转换成二进制类型(即适合于网络传输的protobuf类型,也就是将结构体类型转换为protobuf类型),反序列化后直接写入(转换)对应的结构体类型(也就是将protobuf类型转换为对应的结构体类型)。
测试结果
D:/go/src/pb/pb.exe [D:/go/src/pb]
Students信息为: person:<name:"jz01" age:23 address:"cq" cn:class2 > person:<name:"jz02" age:25 address:"cd" cn:class3 > school:"cqu"
序列化之后的信息为: [10 14 10 4 106 122 48 49 16 23 26 2 99 113 32 1 10 14 10 4 106 122 48 50 16 25 26 2 99 100 32 2 18 3 99 113 117]
反序列化之后的信息为: person:<name:"jz01" age:23 address:"cq" cn:class2 > person:<name:"jz02" age:25 address:"cd" cn:class3 > school:"cqu"
name:"jz01" age:23 address:"cq" cn:class2
name:"jz02" age:25 address:"cd" cn:class3
成功: 进程退出代码 0.
本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/15253788.html