用一個例子說說gRPC的四種服務方法
- 2020 年 4 月 6 日
- 筆記
本文通過一個簡單的例子來演示這4種類型的使用方法
案例程式碼:https://github.com/codeAB/grpc-sample-example
目錄結構說明 ├── calculator.proto # 定義 protobuf ├── client │ ├── client.go # 客戶端 │ ├── gencode │ │ └── calculator.pb.go # protoc-gen-go中間件生成的go中間程式碼 │ ├── go.mod │ └── go.sum ├── README.md └── server ├── gencode │ └── calculator.pb.go # 和上面一樣 ├── go.mod ├── go.sum └── server.go # 服務端
client和server是兩個完全獨立的項目,所以protoc-gen-go生成的中間程式碼並沒有公用,
而是放到各自單獨的項目中,實際上兩者內容是完全一樣的
首先來看 calculator.proto
syntax = "proto3"; package rpc.calculator.test; service Calculator { //簡單模式 rpc Add (TwoNum) returns (Response) {} //服務端流 rpc GetStream (TwoNum) returns (stream Response) {} //客戶端流 rpc PutStream (stream OneNum) returns (Response) {} //雙向流 rpc DoubleStream (stream TwoNum) returns (stream Response) {} } message TwoNum { int32 a = 1; int32 b = 2; } message Response { int32 c = 1; } message OneNum{ int32 a = 1; }
這裡定義了一個計算器服務,包含四個方法,這個四個方法分別演示了個RPC的四種服務類型
下面分別介紹這個四個方法是做什麼的:
1. 客戶端發送一個請求,包含兩個數字,服務端是返回兩個數字的和,這種最基本也是最常用的叫簡單模式,
客戶端發送一次,服務端返回一次,類似於介面請求
2. 客戶端發送一個請求包含兩個數字,服務端返回多次,第一次返回兩數子和,第二次返回兩數字乘,
這種叫服務端流模式,形象點說就是服務端向客戶端搭了一根單向水管,可以不停的往客戶端發送數據,
客戶端不停的接收,直到接收到服務端發送的結束標記後停止接收
使用場景:
客戶端請求一個數據列表,但是這個數據太多了,不可能一次返回,就可以利用這種模式,
服務端一次返回100條數據,前端一直接收處理
3. 客戶端發送了很多次數據,數據是單個數字,服務端不停的接收數據,客戶端發送結束後服務端返回所有數據的總和,
這就是客戶端流模式,形象點說就是客戶端往服務端搭了一個單向的水管,可以不停的往服務端發送數據,
服務端不停的接收,直到接收到客戶端發送的結束標記後停止接收,處理完數據後一次性返回給客戶端,
4. 客戶端分多次發送數據給服務端,每次數據是兩個數,服務端收到數據後多次返回給服務端,每次返回兩個數之和,
客戶端可以多次給服務端發送數據,服務端可以多次返回數據,這就是雙向流模式,雙方都需要同時處理髮送數據和接收數據,
直到雙方通道流關閉
利用calculator.proto生成go中間程式碼
在項目跟目錄執行:
protoc -I ./ ./calculator.proto --go_out=plugins=grpc:./server/gencode protoc -I ./ ./calculator.proto --go_out=plugins=grpc:./client/gencode
分別在 ./server/gencode 和 ./client/gencode 兩個目錄生成了相同的go中間程式碼
有了中間程式碼後就可以編寫服務端server.go了,由於篇幅限制,這裡就不貼完整程式碼了,只對幾個關鍵點做分析
導入中間程式碼
import pb "rpcserver/gencode"
定義了一個server,繼承自 UnimplementedCalculatorServer
type server struct { pb.UnimplementedCalculatorServer }
這裡有個技巧,打開calculator.pb.go你會發現,
UnimplementedCalculatorServer類已經”實現”了我們在calculator.proto中定義的所有個方法
type UnimplementedCalculatorServer struct { } func (*UnimplementedCalculatorServer) Add(ctx context.Context, req *TwoNum) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Add not implemented") } ....
如果你是新手,可以直接粘貼到server,稍作修改就可以了,函數體還是得自己寫
func (s *server) Add(ctx context.Context, in *pb.TwoNum) (*pb.Response, error) { return &pb.Response{C: in.A + in.B}, nil }
其實gRPC的函數不多,定義也非常清晰,比如在寫下面這個方法的時候
func (s *server) GetStream(in *pb.TwoNum, pipe pb.Calculator_GetStreamServer) error { _ = pipe.Send(&pb.Response{C: in.A + in.B}) time.Sleep(time.Second * 2) _ = pipe.Send(&pb.Response{C: in.A * in.B}) return nil }
我也不知道有Send方法,如果用的GoLand,pipe點一下,能用的函數就出來了,就幾個,一看就知道什麼作用,
全程都沒有用到godoc,當然我還是推薦你仔細看一下文檔 https://godoc.org/google.golang.org/grpc
在來看一下客戶端client.go
導入中間程式碼
import pb "rpcclient/gencode"
客戶端感覺沒什麼重點可以說,直接看程式碼吧,每個函數都有相應的備註