我們今天來介紹,一個新的 protocal grpc,它是基於 protobuf 這個由 google 推出來,號稱比 json 更方便、更快速、更簡短的一種溝通格式。

grpc 其實重點很簡單,就是你定義出來的東西,不只代表格式,也代表你伺服器的接口,所以不管在 client 端或 server 端,只要遵照這個 grpc 格式下去實作,api 就接起來,也省去之前用 restful api ,server 端要寫一堆 router ,也不用另外寫文件,剛好符合一句話 『程式碼即文件』,大家遵照 grpc 的契約各自去實作。

再開始介紹之前,有一些基礎工具要先安裝,首先執行下面指令,安裝 grpc

go get -u google.golang.org/grpc

再來安裝

go get -u github.com/golang/protobuf/protoc-gen-go

grpc 宣告

接下來就能來介紹正題,我們來介紹一下,基礎的 grpc 格式宣告

//這邊使用 proto3 的格式 也就是 protobuf 第三版的意思,要注意,第二版跟第三版有一些語法上的差異喔
syntax = "proto3";

package example;

//定義了一個 EchoServer
service EchoServer {
    rpc Echo (EchoRequest) returns(EchoReply){}
}

//定義了 Echo Server EchoRequest
message EchoRequest {
    string message = 1;
}

//定義了 Echo Response
//這裡多回傳了一個 叫做 unixtime
message EchoReply {
    string message = 1;
    int64 unixtime = 2;
}

上面這樣就是一個簡易的 grpc 的宣告,更多型別上可以參閱官網

接下來,在你撰寫這隻檔案的地方,執行

protoc --go_out=plugins=grpc:. *.proto

就會看到產生出一個另一個有帶 pb.go 的檔案,接下來我們分別來實作 client 、server 端

grpc client

func main() {
	conn, err := grpc.Dial("localhost:9999", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("連線失敗:%v", err)
	}
	defer conn.Close()

	c := pb.NewEchoClient(conn)

	r, err := c.Echo(context.Background(), &pb.EchoRequest{Msg: "HI HI HI HI"})
	if err != nil {
		log.Fatalf("無法執行 Plus 函式:%v", err)
	}
	log.Printf("回傳結果:%s , 時間:%d", r.Msg, r.Unixtime)

}

grpc server


type EchoServer struct{}

func (e *EchoServer) Echo(ctx context.Context, req *pb.EchoRequest) (resp *pb.EchoReply, err error) {

	log.Printf("receive client request, client send:%s\n", req.Msg)
	return &pb.EchoReply{
		Msg:      req.Msg,
		Unixtime: time.Now().Unix(),
	}, nil

}

func main() {
	apiListener, err := net.Listen("tcp", ":9999")
	if err != nil {
		log.Println(err)
		return
	}

	// 註冊 grpc
	es := &EchoServer{}

	grpc := grpc.NewServer()
	//pb.Re(grpc, es)
	pb.RegisterEchoServer(grpc, es)

	reflection.Register(grpc)
	if err := grpc.Serve(apiListener); err != nil {
		log.Fatal(" grpc.Serve Error: ", err)
		return
	}
}

最後只要先啟動 grpc server,再執行 grpc client ,就能看到有相對應的訊息連接上了。

上述範例,全部原始碼都放在 github,下載回來 go build 過,即可執行

如有碰上 port 衝突,請自行修改可以執行的 port。