go使用protobuf初接触
记录一下从零开始在go中使用protobuf通信.
1 下载protoc.exe
https://github.com/google/protobuf/releases
我下载的是protoc-xxx-win32.zip,在windows上这个直接包含exe,免去编译。
同时把exe拷贝到$GOPATH/bin目录下,因为后面gofaster也在这目录,所以放一起,执行命令时能找到.。把目录加到环境变量中.
安装protobuf库
go get github.com/golang/protobuf/proto
执行后就会在$GOPATH/pkg/和$GOPATH/src下面有相相应代码和.a库文件
gogoprotobuf 插件
go get github.com/gogo/protobuf/protoc-gen-gofast
执行后还需要install一下生成一堆exe .我是用的LiteIDE install all的,也比较方便
测试
此时随便找个文件夹建个.proto文件即可以
1 2 3 4 5 6 7 8
| syntax = "proto3"; package example; message UserInfo{ string name = 1; int32 age = 2; }
|
第一行网上说是必须指定是proto2还是proto3.后面就随意了
protoc –gofast_out=. example.proto
顺利执行的话会生成example.pb.go文件
内容太多,就不贴了。
最后是正式使用时这些.proto文件和.pb.go文件的位置问题,下一节会再来。
使用
所有基本环境已经搭建完成,接下来正式使用:
在$GOPATH/src下面建目录protocol表示协议相关的文件.
protocol/proto放*.proto文件,生成的.pb.go文件放在protocol/pbgo/目录下面
注意这里.proto文件的package应写为pbgo,与生成的目录名相同.方便后面install和import
src
└─protocol
├─pbgo
└─proto
所以需要在src/protocol/目录下建个脚本生成所有.pb.go文件,关键语句为protoc --gofast_out=./../pbgo xxx.proto
.批量生成代码如下(bat文件)
1 2 3 4 5 6 7 8 9
| cd %~dp0 @echo off for %%i in (proto/*.proto) do ( echo %%i protoc -I=proto --gofast_out=pbgo proto/%%i ) pause
|
这样就会在/protocol/pbgo/目录下生成对应的pb.go文件
然后在/protocol/pbgo目录下go install。这样就会生成$GOPATH/pkg/protocol/pbgo.a库文件。(其实这一步也可以写在上面的.bat批处理里面)
此时在src的其他项目中我们就可以import "protocol/pbgo"
把协议包包含进来使用
实践
根据上面的操作后,新建客户端和服务端代码通信试试:
我实践用例是客户端把今日日期和天气传给服务端。
所以proto:
1 2 3 4 5 6 7 8 9
| syntax = "proto3"; package pbgo; message TodayInfo { int32 year = 1; int32 month = 2; int32 day = 3; string weather = 4; }
|
Server.go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| package main import ( "fmt" "io" "net" "os" "protocol/pbgo" "github.com/gogo/protobuf/proto" ) func onAccept(conn net.Conn) { defer conn.Close() var msg []byte = make([]byte, 2048) for { n, err := conn.Read(msg) if err != nil { if err == io.EOF { break } fmt.Println("Read Error", err.Error()) break } data := msg[:n] todayInfo := &pbgo.TodayInfo{} err = proto.Unmarshal(data, todayInfo) if err != nil { fmt.Println("Unmarchal Error", err.Error()) break } fmt.Printf("Year[%d] Month[%d] Day[%d] Weather[%s]\n", todayInfo.GetYear(), todayInfo.GetMonth(), todayInfo.GetDay(), todayInfo.GetWeather()) } } func main() { listen, err := net.Listen("tcp", ":2333") if err != nil { fmt.Println(err.Error()) os.Exit(1) } defer listen.Close() fmt.Println("Listen Success") for { conn, err := listen.Accept() if err != nil { fmt.Println("Aceept Error:", err.Error()) break } fmt.Println("Accept:", conn.LocalAddr().String(), conn.RemoteAddr().String()) go onAccept(conn) } }
|
Client.go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package main import ( "fmt" "net" "os" "protocol/pbgo" "sync" "time" "github.com/gogo/protobuf/proto" ) func onConnect(conn net.Conn, mux *sync.WaitGroup) { defer mux.Done() defer conn.Close() todayInfo := &pbgo.TodayInfo{ Year: 2018, Month: 7, Day: 9, Weather: "非常热", } data, err := proto.Marshal(todayInfo) if err != nil { fmt.Println("Send Error:", err.Error()) return } conn.Write(data) time.Sleep(1 * time.Second) } func main() { conn, err := net.Dial("tcp", "127.0.0.1:2333") if err != nil { fmt.Println("Connect Error:", err.Error()) os.Exit(1) } fmt.Println("Connect Success") mux := sync.WaitGroup{} mux.Add(1) go onConnect(conn, &mux) mux.Wait() }
|
分别install后,先打开server.exe再打开client.exe
server端结果显示如下:
1 2 3
| Listen Success Accept: 127.0.0.1:2333 127.0.0.1:56355 Year[2018] Month[7] Day[9] Weather[非常热]
|
到此。便可告一段落了.