如果你对Google Protocol Buffer不了解,可以先看下我这篇文章里收集的中文资料:关于Google Protocol Buffer的中文资料
源码地址:https://code.google.com/p/goprotobuf/
详细的介绍:https://code.google.com/p/goprotobuf/source/browse/README
介绍:
This software has two parts: a ‘protocol compiler plugin’ that generates Go source files that, once compiled, can access and manage protocol buffers; and a library that implements run-time support for encoding (marshaling), decoding (unmarshaling), and accessing protocol buffers.
大意:
该软件包含两部分:protoc-gen-go:一旦使用’协议编译器插件‘编译,会生成一些go的源码文件,可以访问和管理protocol buffers;proto:是一个实现运行时支持,为编码(编组),解码(解编)的库,和访问protocol buffers。
简单的说,protoc-gen-go是一个编译器,用来把 *.proto协议文件,编译生成 *.pb.go文件。再接下来的例子,我们会介绍如何使用它。
而proto需要包含到我们的软件里,去将消息编码为二进制数据,或者将二进制数据还原为消息对象。
源码下载:
go get -u code.google.com/p/goprotobuf/{proto,protoc-gen-go}
或者直接下载源码到自己的项目里:
hg clone https://code.google.com/p/goprotobuf/
如下图:
编译:
编译成功后,我们会发现bin目录下,会生成protoc-gen-go文件,以及pkg目录下会生成对应的库文件。
接下来,我们编写测试一个例子:
首先,编写test.proto,内容如下:
package example;
enum FOO { X = 17; };
message Test {
required string label = 1;
optional int32 type = 2 [default=77];
repeated int64 reps = 3;
optional group OptionalGroup = 4 {
required string RequiredField = 5;
}
}
接着,编写Makefile文件,用于生成*.pb.go文件,内容如下:
include ../code.google.com/p/goprotobuf/Make.protobuf
all: regenerate
regenerate:
rm -f test.pb.go
make test.pb.go
# The following rules are just aids to development. Not needed for typical testing.
diff: regenerate
hg diff test.pb.go
restore:
cp test.pb.go.golden test.pb.go
preserve:
cp test.pb.go test.pb.go.golden
终端下,make以后,我们会看到生成对应的test.pb.go文件,内容如下:
// Code generated by protoc-gen-go.
// source: test.proto
// DO NOT EDIT!
package example
import proto "code.google.com/p/goprotobuf/proto"
import json "encoding/json"
import math "math"
// Reference proto, json, and math imports to suppress error if they are not otherwise used.
var _ = proto.Marshal
var _ = &json.SyntaxError{}
var _ = math.Inf
type FOO int32
const (
FOO_X FOO = 17
)
var FOO_name = map[int32]string{
17: "X",
}
var FOO_value = map[string]int32{
"X": 17,
}
func (x FOO) Enum() *FOO {
p := new(FOO)
*p = x
return p
}
func (x FOO) String() string {
return proto.EnumName(FOO_name, int32(x))
}
func (x FOO) MarshalJSON() ([]byte, error) {
return json.Marshal(x.String())
}
func (x *FOO) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO")
if err != nil {
return err
}
*x = FOO(value)
return nil
}
type Test struct {
Label *string protobuf:"bytes,1,req,name=label" json:"label,omitempty"
Type *int32 protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"
Reps []int64 protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"
Optionalgroup *Test_OptionalGroup protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"
XXX_unrecognized []byte json:"-"
}
func (this *Test) Reset() { *this = Test{} }
func (this *Test) String() string { return proto.CompactTextString(this) }
func (*Test) ProtoMessage() {}
const Default_Test_Type int32 = 77
func (this *Test) GetLabel() string {
if this != nil && this.Label != nil {
return *this.Label
}
return ""
}
func (this *Test) GetType() int32 {
if this != nil && this.Type != nil {
return *this.Type
}
return Default_Test_Type
}
func (this *Test) GetOptionalgroup() *Test_OptionalGroup {
if this != nil {
return this.Optionalgroup
}
return nil
}
type Test_OptionalGroup struct {
RequiredField *string protobuf:"bytes,5,req" json:"RequiredField,omitempty"
}
func (this *Test_OptionalGroup) Reset() { *this = Test_OptionalGroup{} }
func (this *Test_OptionalGroup) GetRequiredField() string {
if this != nil && this.RequiredField != nil {
return *this.RequiredField
}
return ""
}
func init() {
proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
}
最后,编写测试代码如下:
package main
import (
"log"
"code.google.com/p/goprotobuf/proto"
"example"
"fmt"
)
func main() {
test := &example.Test{
Label: proto.String("hello"),
Type: proto.Int32(17),
Optionalgroup: &example.Test_OptionalGroup{
RequiredField: proto.String("good bye"),
},
}
// print test by string.
fmt.Println(test.String())
data, err := proto.Marshal(test)
if err != nil {
log.Fatal("marshaling error: ", err)
}
// print data
fmt.Println(data)
newTest := &example.Test{}
err = proto.Unmarshal(data, newTest)
if err != nil {
log.Fatal("unmarshaling error: ", err)
}
// Now test and newTest contain the same data.
if test.GetLabel() != newTest.GetLabel() {
log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel())
}
// etc.
}
编译运行,结果如下:
这里只是简单介绍并编写了个测试例子,许多细节并没有介绍,以后有机会再跟大家分享。
有疑问加站长微信联系(非本文作者)