一、为什么要使用protobuf

protobuf 是Google提供一个具有高效的协议数据交换格式工具库。具有序列化/反序列化效率高,空间开销小,传输效率高等优点,并且支持多语言。

二、如何使用protobuf

今天以Golang为例来初探protobuf的使用。以下在mac环境下进行

首先准备软件环境(默认go已经安装,并配置好了GOROOT、GOPATH等环境变量)

1) 安装protobuf

在mac下安装protobuf比较简单,使用brew。命令如下:

$> brew install protobuf

安装成功后我们可以通过查看版本号来确定是否安装成功:

$> protoc --version

如下输出protoc 版本号表示protobuf已经正确安装了

$> libprotoc 3.12.3

2)安装go的protobuf编辑插件

安装前请确认GOPATH环境变量已经正确配置。

$> go get github.com/golang/protobuf/protoc-gen-go

执行以上命令会在$GOPATH下安装两个包:github.com、google.golang.org。并将protobuf的go编译插件 protoc-gen-go 安装到 ${GOPATH}/bin/目录下

注:protoc-gen-go 将安装到 ${GOPATH}/bin/ 目录下,在执行protoc进行编译时保证protoc-gen-go能够被访问到。

使用

环境准备好后,就可以编写一些proto文件来尝试使用它啦,开始吧

首先创建一个proto文件(本例为addressbook.proto)来定义需要序列化传输的数据结构,如下:

syntax = "proto3";			//声明使用proto3协议语法package protoTest;			//执行生成的go文件的包名import "google/protobuf/timestamp.proto";		//引入其他proto文件内容option go_package = "config/protoTest";			//指定编译后生成的go文件的路径/*如该配置生成的go文件将会在项目目录下的 src/config/protoTest/目录下 *///以下为消息的定义message Person {  int32 id 			= 1;    string name 	= 2;    string email 	= 3;      //内嵌类型    enum phoneType {    MOBILE 	= 0;        HOME 		= 1;        WORK 		= 2;    }  message phoneNumber {    string number 	= 1;        phoneType type 	= 2;  		//使用内嵌的自定义类型  }  //end      repeated phoneNumber phones = 4;  	//使用内嵌的自定义类型  /**   * repeated表示该字段会在消息内0次或多次出现,生成go文件后该字段会是一个*phoneNumber类型的切片   * 此外protobuf 还有 required 表示必选字段, optional表示可选字段   */  google.protobuf.Timestamp update_at = 5;}message AddressBook {  repeated Person person = 1;}

定义好了proto文件后我们需要对proto文件进行编译,编译后将生成对应于proto文件内定义的go数据结构定义文件。

protoc -I=指定为项目的src目录 -go_out=指定为项目的src目录 proto文件路径

本例项目目录结构为:

go-protobuf   |_ src        |_ config                |_ addressbook.proto        |_ github.com        |_  google.golang.org

在src目录下执行如下命令:

$> protc -I=./ -go_out=./ config/addressbook.proto 

如果没有语法错误将会在src/config/protoTest/目录多了一个addressbook.pb.go文件(文件内容比较多,这里就不贴了)。

使用时首先引入包

import (    "github.com/golang/protobuf/proto"    pb "config/protoTest"					//proto文件中指定的 go_package)

序列化:

p := &pb.Person{}pn := &pb.PersonPhoneNumber{    Number: "123456",    Type: 0,}p.Phones = append(p.Phones, pn)book := &pb.AddressBook{}book.Person = append(book.Person, p)out, err := proto.Marshal(book)		//序列化成[]byte类型的数据

序列化后就可以将内容进行网络传输或者保存到文件中了。

反序列化:

in, err := ioutil.ReadFile(fname)			//从文件中读取序列化后的内容if err != nil {    log.Fatalln("Error reading file:", err)}book := &pb.AddressBook{}if err := proto.Unmarshal(in, book); err != nil {		//反序列化,得到AddressBook结构体    log.Fatalln("Failed to parse address book:", err)}

以上就是在go中使用protobuf的简单尝试了。以后如果项目中用到将会进行深入学习并进行更新。

本文示例中参考了github 中的代码,完整代如下:

https://github.com/protocolbuffers/protobuf.git