protobuf在go中的应用

protobuf是一个跨语言的传输协议格式,其功能和json类似. protobuf和json不同的是proto使用二进制进行传输,速度上会比json效率高. 但是在可读性上比json差.

protobuf底层使用C++实现的.但现在已经支持很多的语言使用了.目前支持:C++,java,python,objective-c,c#, javascript, ruby, go, php, Dart. 在这里讲protobuf在go中的使用.我使用的环境是ubuntu 16.04

在使用之前需要安装proto的基础包.基础包是C++编写的,所以需要用到编译C++一些常规的环境,这里不具体介绍.

安装go的环境

再者获取go相关的插件包:go get -u github.com/golang/protobuf

获取之后进入相应的文件夹,使用go build , go install进行编译和安装.使用命令:proto --version测试是否成功安装.

chenmei@bogon:~/go/src/test/protobuf$ protoc --version 
libprotoc 2.6.1

下面我们就看一个使用的例子,先写一个proto的原文件,这里以学生以及和学生管理的考试成绩为例子:

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;
}

上面就定义了课程,学生,以及学生的列表这几个结构.

使用命令进行转换:

protoc --go_out=. Studentlist.proto

当转换完成会生成如下的文件:

// 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

转载于:https://my.oschina.net/u/1013544/blog/3031466

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值