Protocol buffers介绍及与golang结合使用

定义

Protocol buffers是一个灵活、高效、自动化地序列化结构化数据的方案。类似于XML,但是更快、更小和更灵活。你只需要定义一次数据的结构,就可以使用多种语言从多种数据流中读取结构化数据,并进行操作。而且可以很方便的变更数据的结构,而且不影响基于变更前的数据结构的程序。
在golang中,protocol buffers可以基于不同的传输协议进行传输,如HTTP/2和AMQP(Advanced Message Queuing Protocol)。
Protocol buffers是一个类似JSON的传输格式,但是是强类型的、只能被服务器端和客户端理解,人是无法阅读的。即以二进制的方式进行传输,

优势

Protocal buffers和JSON或XML在序列化结构化数据方面进行对比,具有如下的优势:

  • 它是强类型的;
  • 它的体积更小;
  • 在序列化和反序列化时,速度更快;
  • 由于具有类型和序号,它更加清晰,不容易混淆;
  • 它会产生数据访问的类,对编程更加友好;

使用

编译

protoc编译器会自动的基于.proto文件生成Go的结构体。这些结构体后期就会被导入到项目中进行业务处理,参与到序列化、反序列化的过程中。

安装编译器

安装编译器的方式根据操作系统的不同而不同,具体可参考:

github网址
具体到mac上,只要使用如下命令即可:

brew install protobuf

注意
在我们安装完成后,实际上是无法从.proto文件生成golang文件的,它会显示如下错误信息:
编译错误
这个错误实际上是在提示我们我们还没有安装能产生golang文件文件的插件,因为在安装protobuf,它只是安装如下的语言插件:
默认插件
下面我们就来解决这个问题,即安装golang的插件:

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

编译器的插件protoc-gen-go会安装到 G O P A T H / b i n GOPATH/bin目录下,除非我们设置了 GOBIN环境变量。 G O P A T H / b i n GOPATH/bin或 GOBIN必须在$PATH里,否则编译器protoc是无法找到它的。

编写proto文件

具体的内容如下:

syntax = "proto3";

package protofiles;

message Person {
    string name = 1;
    int32 id = 2;
    string email = 3;
    enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }
    message PhoneNumber {
        string number = 1;
        PhoneType type = 2;
    }

    repeated PhoneNumber phones = 4;
}

message AddressBook {
    repeated Person persons = 1;
}

编译文件

在我们编写好proto文件后,我们可以通过如下命令进行文件的编译:

protoc --go_out=. *.proto

这个命令会发现当前目录下的所有的proto文件,并转化为golang文件。golang的文件名与proto文件名相同。当运行完此命令后,在当前目录下会生成一个新的golang文件:person.pb.go。如果我们打开这个文件,就会看到自动生成的文件内容:

type Person_PhoneType int32

const (
	Person_MOBILE Person_PhoneType = 0
	Person_HOME   Person_PhoneType = 1
	Person_WORK   Person_PhoneType = 2
)

var Person_PhoneType_name = map[int32]string{
	0: "MOBILE",
	1: "HOME",
	2: "WORK",
}

var Person_PhoneType_value = map[string]int32{
	"MOBILE": 0,
	"HOME":   1,
	"WORK":   2,
}

func (x Person_PhoneType) String() string {
	return proto.EnumName(Person_PhoneType_name, int32(x))
}

func (Person_PhoneType) EnumDescriptor() ([]byte, []int) {
	return fileDescriptor_4c9e10cf24b1156d, []int{0, 0}
}

type Person struct {
	Name                 string                `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
	Id                   int32                 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"`
	Email                string                `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"`
	Phones               []*Person_PhoneNumber `protobuf:"bytes,4,rep,name=phones,proto3" json:"phones,omitempty"`
	XXX_NoUnkeyedLiteral struct{}              `json:"-"`
	XXX_unrecognized     []byte                `json:"-"`
	XXX_sizecache        int32                 `json:"-"`
}

使用

在生成完数据的golang文件后,我们就可以基于结构体进行使用了。

序列化和反序列化

package main

import (
	pb "awesomeProject/protobufs"
	"github.com/golang/protobuf/proto"
	"log"
)

func main() {
	p := &pb.Person{
		Id:1234,
		Name: "Roger F",
		Email: "[email protected]",
		Phones: []*pb.Person_PhoneNumber{
			{Number:"555-4321", Type: pb.Person_HOME},
		},
	}
	log.Println(p)
	p1 := &pb.Person{}
	body, _ := proto.Marshal(p)
	_ = proto.Unmarshal(body, p1)
	log.Printf("%v", p1)
}

在执行上述程序后会显示如下信息:
console message

Protocol buffers和JSON

在golang中使用protocol buffers的另一个好处是,基于编译proto文件生成的结构体,我们可以很容易的生成JSON格式的字符串,具体代码如下:

func main() {
	p := &pb.Person{
		Id:1234,
		Name: "Roger F",
		Email: "[email protected]",
		Phones: []*pb.Person_PhoneNumber{
			{Number:"555-4321", Type: pb.Person_HOME},
		},
	}
	log.Println(p)
	body, _ := json.Marshal(p)
	log.Println(string(body))
}

在执行上述程序后会显示如下信息:
console message

为什么使用protocol buffers

  • 首先protocol buffers是为了后台系统间以强类型、小负载的方式通信而存在的。因为二进制文件普遍比文本文件小,所以protocal buffers生成的二进制文件要比JSON的文本文件小很多;
  • 结合gPRC会显著的提高数据传输效率;
发布了6 篇原创文章 · 获赞 6 · 访问量 596

猜你喜欢

转载自blog.csdn.net/qq_20996551/article/details/105403456