1. 程式人生 > >go語言學習-------Go語言中使用 protobuf

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

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.protopackage 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.Marshalvar _ = math.Inf

type MyMsgstruct{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}return0}

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}return0}

func init(){}

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


下面寫一個測試程式:

// main.gopackage 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. 參考