1. 程式人生 > >用一個例子說說gRPC的四種服務方法

用一個例子說說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"

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

&n