是在了解微服務的同時,得知 Go 並且同時聽聞了 gRPC
所以現在來學習使用 gRPC,看看 gPRC 到底是哪裡特別
Require
首先需要安裝 gPRC 工具,撰寫好 gPRC 的 pb 文件之後,就能透過 protoc 轉換成 go 文件進行使用
1
2
|
go get -u google.golang.org/grpc
go get -u github.com/golang/protobuf/protoc-gen-go
|
目錄
此次練習的目錄結構
.
├── go.mod
├── go.sum
├── proto
│ └── hello.proto
├── rpc
│ └── hello.pb.go
├── client
│ └── main.go
└── server
└── main.go
撰寫
Proto
撰寫 proto 定義文件,此為官方文件 go - quickstart
proto3 及 proto2 的程式文法不同,所以版本注意
syntax = "proto3";
option go_package= ".;rpc";
service Greeter {
rpc Hello (Request) returns (Response){};
}
message Request {
string greeting = 1;
}
message Response {
string reply = 2;
}
complier
將官方範例編譯成 go 檔
將 proto 底下副檔名為 .proto
轉換成 go 文件並放入 rpc 目錄中
1
|
protoc proto/*.proto --go_out=plugins=grpc:rpc
|
Server
- TCP 監聽指定埠
- 註冊 gRPC 函式
- 啟用 gRPC Server 監聽指定埠
並且要根據 SayHello 撰寫函式進行回覆處理
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
|
package main
import (
"context"
"log"
"net"
pb "github.com/cody0704/grpc_example01/rpc"
"google.golang.org/grpc"
)
type server struct {
}
func (s *server) SayHello(ctx context.Context, in *pb.Request) (*pb.Response, error) {
log.Printf("Received: %v", in.GetGreeting())
return &pb.Response{Reply: "Hello, " + in.GetGreeting()}, nil
}
func main() {
addr := "127.0.0.1:9999"
lis, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
log.Println("Server listening on", addr)
gRPCServer := grpc.NewServer()
pb.RegisterGreeterServer(gRPCServer, &server{})
if err := gRPCServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
|
Client
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
|
package main
import (
"context"
"log"
"time"
pb "github.com/cody0704/grpc_example01/rpc"
"google.golang.org/grpc"
)
func main() {
addr := "127.0.0.1:9999"
conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("Can not connect to gRPC server: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
res, err := c.SayHello(ctx, &pb.Request{Greeting: "Cody"})
if err != nil {
log.Printf("Could not get nonce: %v", err)
}
log.Println("Response:", res.GetReply())
}
|
Run
將以上的程式進行執行,首先需要啟動 Server 再啟動 Client
1
2
3
4
5
6
7
8
|
# terminal 1
go run server/main.go
> 2020/09/18 10:55:23 Server listening on 127.0.0.1:9999
> 2020/09/18 10:56:04 Received: Cody
# terminal 2
go run client/main.go
> 2020/09/18 10:56:04 Response: Hello, Cody
|
結論
目前個人理解的是跟一般直接用傳輸協議接收之後進行還要針對內容進行對應處理不太一樣
撰寫 pb 文件時就已經做好這個部分,只要針對 proto 文件及 Request 的邏輯處理
Ref
- https://grpc.io/
- go - quickstart