Golang中使用protobuf高效编码
Protocol Buffers 是Google推出的一种数据交换格式。二进制、高性能、跨平台、跨编程语言。很适合现在分布式、微服务中结合消息总线做高性能数据交换。
定义 *.proto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| syntax = "proto3"; package tutorial;
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 people = 1; }
|
编译 *.proto
先安装protobuf 3.0 C++实现 (目前mac上brew还没有正式版,虽然官方已经发布正式版)
1
| brew install protobuf --devel
|
安装Golang代码生成器插件
官方的
go get -u github.com/golang/protobuf/protoc-gen-go
gogo优化版(快5-7倍,性能对比)
1 2 3
| go get github.com/gogo/protobuf/proto go get github.com/gogo/protobuf/protoc-gen-gogo go get github.com/gogo/protobuf/gogoproto
|
生成Golang *.pb.go
代码
官方用法
1
| protoc --go_out=. *.proto
|
gogo优化用法
protoc --gofast_out=. *.proto
使用 *.pb.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package main
import ( "fmt" "log"
"github.com/gogo/protobuf/proto"
pb "demo/protobuf/tutorial" )
func main() { p := &pb.Person{ Id: 1234, Name: "Jerry Hou", Email: "https@yryz.net", Phones: []*pb.Person_PhoneNumber{ {Number: "110", Type: pb.Person_HOME}, {Number: "911", Type: pb.Person_WORK}, }, }
out, err := proto.Marshal(p) if err != nil { log.Fatal("failed to marshal: ", err) }
p2 := &pb.Person{} if err := proto.Unmarshal(out, p2); err != nil { log.Fatal("failed to unmarshal: ", err) }
fmt.Println(p2) fmt.Println(out) fmt.Println(string(out))
}
|
在网络编程中使用
需要自己再封装消息长度(使用 nsq这类消息总线可以省略)、消息类型、protobuf编码后的消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package protocol
type MsgType uint8
const ( CommonMsgType MsgType = 0 ScanRequestMsg MsgType = 1 ScanResponseMsg MsgType = 2 ScanDoneMsg MsgType = 3 )
func (m MsgType) Encode(pbMsg []byte) []byte { return append([]byte{byte(m)}, pbMsg...) }
func (m MsgType) Decode(msg []byte) (mt MsgType, pbMsg []byte) { mt = MsgType(msg[0]) pbMsg = msg[1:] return }
|