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