是在了解微服務的同時,得知 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

  1. TCP 監聽指定埠
  2. 註冊 gRPC 函式
  3. 啟用 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

  1. https://grpc.io/
  2. go - quickstart