個簡單的講,protobuf是相似於json和xml的一種序列化數據的方法,它比後二者更簡單、更快、序列化後的數據長度更短。php
這裏用作了一個php發送protobuf數據,用golang開發的server端接收數據的demo。git
注:github
本機已安裝好protobuf。golang
第一步,編寫pb文件
編寫一個簡單的pb文件,命名爲hello.proto,代碼內容爲:json
syntax = "proto3"; package lm; message helloworld { int32 id = 1; // ID string str = 2; // str int32 opt = 3; // optional field }
第二步,編寫php發送端
- 切換到pb文件所在目錄,執行命令:
protoc --php_out=./ hello.proto
執行成功後,會生成相關基礎類文件。bash
2. 新建一個發送端文件sender.php,經過socket發送內容給服務端。代碼內容爲:dom
<?php include './GPBMetadata/Hello.php'; include './Lm/helloworld.php'; use Lm\helloworld; $from = new helloworld(); $from->setId(1); $from->setStr('窗前明月光,疑是地上霜。'); $from->setOpt(random_int(1000, 9999)); $data = $from->serializeToString(); $fp = fsockopen('127.0.0.1', 10011, $errno, $errmsg); if (!$fp) { echo "error:\t" . $errmsg . "\n"; } else { fwrite($fp, $data); $answer = ''; while (!feof($fp)) { $answer .= fgets($fp, 128); } fclose($fp); echo $answer . "\n"; }
第三步,使用go編寫服務端socket
- 執行命令,生成基礎文件:
protoc --go_out=. *.proto
- 編寫server.go文件,監聽10011端口。代內容爲:
package main import ( "log" "net" "protobufdemo/putils" "time" ) func main() { addr := "localhost:10011" // 建立socket文件描述符,綁定ip:port,改變socket狀態爲監聽狀態 ln, err := net.Listen("tcp", addr) // 返回時關閉tcp鏈接 defer ln.Close() if err != nil { panic(err) } log.Println("begin listen on:", addr) for { // 從socket recive隊列裏獲取一個創建好的鏈接 conn, err := ln.Accept() if err != nil { panic(err) } // 新起一個goroutine處理鏈接 go handler(conn) } } func handler(conn net.Conn) { buffer := make([]byte, 2048) //創建一個slice for { n, err := conn.Read(buffer) //讀取客戶端傳來的內容 if err != nil { log.Println(err) return //當遠程客戶端鏈接發生錯誤(斷開)後,終止此協程。 } dataReceived := string(buffer[:n]) log.Println(conn.RemoteAddr().String(), "receive data string:\n", dataReceived) dataDecode, err := putils.DecodeData(dataReceived) if err != nil { log.Println(err) return } log.Println(dataDecode.Id) log.Println(dataDecode.Str) log.Println(dataDecode.Opt) //返回給客戶端的信息 strTemp := "CofoxServer got msg \"" + string(buffer[:n]) + "\" at " + time.Now().String() conn.Write([]byte(strTemp)) // 關閉鏈接 conn.Close() break } }
其中DecodeData方法內容:tcp
package putils import ( "github.com/golang/protobuf/proto" "protobufdemo/lm" ) func DecodeData(data string) (*lm.Helloworld, error) { result := &lm.Helloworld{} err := proto.Unmarshal([]byte(data), result) return result, err }