天天看點

go語言學習-------Go語言中使用 protobuf

Go語言中使用 protobuf

2016年05月03日

protobuf以前隻支援C++, Python和Java等語言, Go語言出來後, 作為親兒子, 那有不支援的道理呢? github位址: go protobuf.

1. 安裝protobuf

<1> 去這兒下載下傳protobuf git clone  https://github.com/google/protobuf.git 運作autogen.sh安裝擷取protobuf編譯器protoc編譯器,也可以按照下面的步驟安裝:
./configure
make
make install
protoc   -h      
<2> 擷取并安裝proto-gen-go, 

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

, 這條指令會生成protoc-gen-go的可執行檔案

<3> 注意将protoc-gen-go可執行檔案路徑加到PATH環境變量中, 或者将protoc-gen-go可執行檔案放到類似于/usr/local/bin這樣的路徑下, 隻要在PATH路徑下就OK. 原因在于, protoc-gen-go可執行檔案需要被protoc調用.

<4> 擷取 goprotobuf 提供的支援庫,包含諸如marshal、unmarshal等功能, 使用指令 

go get github.com/golang/protobuf/proto

.

<5> 寫一個test.proto檔案,執行protoc test.proto --go_out=.生成go語言的代碼,如果提示libprotoc.so找不到,需要把/usr/local/lib 添加到LD_LIBRARY_PATH環境變量中。

2. 使用protobuf

首先我們需要寫一個test.proto檔案, 在這個檔案中可以定義需要的結構, 例如枚舉型, 結構體等等. 那麼首先我自己定義了一個結構如下所示,

// test.proto
 package test;
 message myMsg
 {
    required int32     id = 1;   // ID
    required string    str = 2;  // str
    optional int32     opt = 3;  //optional field
 }           

注意required是必須要求的字段, optional是可選字段. 同時注意, id=1, 後面的數字僅僅是一個unique标志而已, 保證唯一性就OK! 

然後使用protoc test.proto --go_out=. 編譯這個檔案, 生成的檔案名稱為test.pb.go檔案! 如果這個路徑下有多個檔案需要編譯, 那麼執行protoc --go_out=. *.proto就可以. 注意--go_out=後面的參數是生成的檔案的路徑, 本文生成的檔案在'.'目前路徑下. 

生成的代碼如下:

// Code generated by protoc-gen-go.
// source: 1.proto
// DO NOT EDIT!

/*
Package test is a generated protocol buffer package.

It is generated from these files:
    1.proto

It has these top-level messages:
    MyMsg
*/
package test

import proto "github.com/golang/protobuf/proto"
import math "math"

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = math.Inf

type MyMsg struct {
    Id               *int32  `protobuf:"varint,1,req,name=id" json:"id,omitempty" bson:"id,omitempty"`
    Str              *string `protobuf:"bytes,2,req,name=str" json:"str,omitempty" bson:"str,omitempty"`
    Opt              *int32  `protobuf:"varint,3,opt,name=opt" json:"opt,omitempty" bson:"opt,omitempty"`
    XXX_unrecognized []byte  `json:"-"`
}

func (m *MyMsg) Reset()         { *m = MyMsg{} }
func (m *MyMsg) String() string { return proto.CompactTextString(m) }
func (*MyMsg) ProtoMessage()    {}

func (m *MyMsg) GetId() int32 {
    if m != nil && m.Id != nil {
        return *m.Id
    }
    return 0
}

func (m *MyMsg) GetStr() string {
    if m != nil && m.Str != nil {
        return *m.Str
    }
    return ""
}

func (m *MyMsg) GetOpt() int32 {
    if m != nil && m.Opt != nil {
        return *m.Opt
    }
    return 0
}

func init() {
}           

特别注意: 生成的檔案中的package是test, 那麼檔案必須放在test檔案夾下! 否則會報錯: "can't load package: package test: found packages test (test.pb.go) and main (main.go)"

下面寫一個測試程式:

// main.go
package main

import (
    "fmt"
    t "./test"
    "github.com/golang/protobuf/proto"
)

func main(){
    // 建立一個對象, 并填充字段, 可以使用proto中的類型函數來處理例如Int32(XXX)
    hw := t.MyMsg{
        Id: proto.Int32(1),
        Str: proto.String("iyviasbjasdv"),
        Opt: proto.Int32(2),

    }

    // 對資料進行編碼, 注意參數是message指針
    mData, err := proto.Marshal(&hw)

    if err != nil {
        fmt.Println("Error1: ", err)
        return
    }

    // 下面進行解碼, 注意參數
    var umData t.MyMsg
    err = proto.Unmarshal(mData, &umData)

    if err != nil {
        fmt.Println("Error2: ", err)
        return
    }

    // 輸出結果
    fmt.Println(*umData.Id, "  ", *umData.Str, "  ", *umData.Opt)
}
           

簡單的用法完畢, 然後我們就能愉快地使用protobuf定義自己的消息協定了, 贊! 

隻有protobuf中的編解碼原理, 有時間再去深究了~~~

2. 參考

go protobuf

proto文檔