這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
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用出來並非那麼方便。
(完)