用一個例子說說gRPC的四種服務方法

本文通過一個簡單的例子來演示這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"

客戶端感覺沒什麼重點可以說,直接看程式碼吧,每個函數都有相應的備註