Golang + Protobuf 構造通訊協議

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Golang 用於寫網路通訊非常方便,其中訊息通訊就可能會用到跨語言的Protobuf。本文講述如何使用Protobuf構造Golang的通訊協議。

(1)Protobuf需要protoc,這個只要在github下載編譯即可安裝。Debian系也可以通過apt來安裝。
(2)第二個是go的外掛程式,這個同樣下載原始碼後,執行go build 和 go install就能安裝在$GOPATH路徑下面,然後把該檔案夾加入$PATH就可以使用了。
(3)撰寫proto檔案,詳情請參考官方文檔。看起來是這樣樣子的:

// poster.protopackage poster;message Mail {    required bytes type = 1;    required bytes md5 = 2;    required bytes path = 3;}

以上是我在socket中用到的訊息格式,分別定義訊息的type,md5的值, path路徑還有檔案的大小,就可以用於接下來的md5檢驗,續傳功能,還有根據訊息類型來自訂不同的訊號。這裡使用bytes不是必須的,只是我在My Code裡面會分別定義各個欄位的長度,byte對於我更直觀。

然後,就是將它變成golang的一個庫import到自己的代碼裡,產生的命令是:

protoc --go_out=. poster.proto

然後我就會得到一個poster.pb.go的檔案,隨後我就可以在My Code裡import這個庫了。但這個庫只是提供了定義格式和讀取資訊的功能。要去將資訊打包成protobuf或解包還需要另外一個庫去支援,可以通過以下命令來達成:

go get github.com/golang/protobuf/proto

關於最基本的Marshal和Unmarshal方法我就不做解釋了,但這裡粘出struct和protoc配合使用的例子,不過不要複製粘貼,這裡有一個utils的庫是自己寫的,主要是把int64轉成byte的方法。另外請注意因為我定在proto檔案裡義了三個欄位都是byte類型,所以我會先將原有的類型轉化成byte類型,但struct裡則是合適的類型方便調用:

// 這裡定義長度主要是因為socket通訊等訊息包假設採用固定長度來接收const (    typeSize   = 8    md5Size    = 32    pathSize   = 80    bufferSize = 126)type msgBuffer struct {    bufType  int    bufMd5   string    bufPath  string}// func (msgBuf *msgBuffer) NewMsg() []byte {    bufType := make([]byte, typeSize)    bufMd5 := make([]byte, md5Size)    bufPath := make([]byte, pathSize)    copy(bufType, utils.Int64ToByte(int64(msgBuf.bufType)))    copy(bufMd5, []byte(msgBuf.bufMd5))    copy(bufPath, []byte(msgBuf.bufPath))    dataText := &poster.Mail {        Type: bufType,        Md5 : bufMd5,        Path: bufPath,    }    data, err := proto.Marshal(dataText)    checkError(err)    return data}

這個data就是可以隨便傳輸的byte array了。最後接收方如下所示,就能將訊息解包並且友好地調用了。(注意utils.FirstNull會自動截取從第一個byte開始連續的到最後一個對應的ASCII非0的字元段,因為假如設定了固定長度,而value的長度沒有那麼長,就會填null)。

func msgParser(data []byte) *msgBuffer {    dataText := &poster.Mail{}    err := proto.Unmarshal(data, dataText)    checkError(err)    msgType := utils.ByteToInt64(dataText.GetType())    msgMd5 := string(dataText.GetMd5())    msgPath := string(dataText.GetPath()[:utils.FirstNull(dataText.GetPath())])    msg := &msgBuffer{int(msgType), msgMd5, msgPath}    return msg}

整個流程很簡單,最麻煩的地方大概就是protobuf用出來並非那麼方便。

(完)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.