golang之grpc入門

環境

  • go版本要求: go 1.6及以上

    C:\> go version
    go version go1.12 windows/amd64
    
  • 設置goproxy及go mod開啓(win cmd)

    set GOPROXY=https://goproxy.io
    set GO111MODULE=on
    
  • 安裝protoc編譯工具(protobuf轉成相應語言代碼的工具)
    下載: https://github.com/protocolbuffers/protobuf/releases/download/v3.9.1/protoc-3.9.1-win64.zip
    並配置protoc到PATH環境變量
    驗證protoc是否安裝成功:

    C:\>protoc --version
    libprotoc 3.9.1
    
  • 相關sdk下載

    go get -u google.golang.org/grpc
    go get -u github.com/golang/protobuf/protoc-gen-go # protoc生成go語言的插件
    

簡單示例

我們以一個"計算器"的例子來入門grpc在go語言中的使用:
示例項目(calculator)結構如下:

D:\workspace\test\grpc\calculator
│  go.mod
│  go.sum
│
├─client
│      client.go
│
├─protobuf
│      calculator.pb.go
│      calculator.proto
│
└─server
        server.go

定義service(calculator.proto)

syntax = "proto3"; // 使用protobuf版本3

option go_package = "protobuf"; // 這個影響生成的目錄及go的package命名

// 定義一個計算服務, 輸入爲CalcRequest, 輸出爲CalcResponse
service CalculatorService {
	rpc calc(CalcRequest) returns (CalcResponse) {};
}

// 計算兩個數某種運算(如加法)的參數
message CalcRequest {
	double a = 1;
	double b = 2;
	string op = 3;
}

// 計算結果
message CalcResponse {
	double r = 1;
}

// cd path/to/calculator
// protoc -I .\protobuf --go_out=plugins=grpc:.\protobuf .\protobuf\calculator.proto

生成.pb.go文件

進入到項目根目錄(calculator根目錄), 執行:

protoc -I .\protobuf --go_out=plugins=grpc:.\protobuf .\protobuf\calculator.proto

則會在calculator/protobuf目錄下生成.pb.go文件

實現rpc service

新建文件: calculator/server/server.go, 內容如下:

package main

import (
	"calculator/protobuf"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"net"
)

// 實現: CalculatorServiceServer接口, 在calculator.pb.go中定義
type server struct {}

func (server) Calc(ctx context.Context, req *protobuf.CalcRequest) (resp *protobuf.CalcResponse, err error) {
	a := req.GetA()
	b := req.GetB()
	op := req.GetOp()
	resp = &protobuf.CalcResponse{}

	switch op {
	case "+":
		resp.R = a + b
	case "-":
		resp.R = a - b
	case "*":
		resp.R = a * b
	case "/":
		if b == 0 {
			err = fmt.Errorf("divided by zero")
			return
		}
		resp.R = a / b
	}
	return
}

// 啓動rpc server
func main() {
	listener, err := net.Listen("tcp", "localhost:3233")
	if err != nil {
		panic(err)
	}

	s := grpc.NewServer()
	protobuf.RegisterCalculatorServiceServer(s, &server{})
	fmt.Println("server start")
	err = s.Serve(listener)
	if err != nil {
		panic(err)
	}
}

生成go.mod

進到項目根目錄執行:

go mod init calculator
go mod tidy

客戶端調用示例

新建文件: calculator/client/client.go, 內容如下:

package main

import (
	"calculator/protobuf"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"log"
)

func main() {
	// 連上grpc server
	conn, err := grpc.Dial("localhost:3233", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}

	defer conn.Close()

	c := protobuf.NewCalculatorServiceClient(conn)
	
	// 調用遠程方法
	resp, err := c.Calc(context.Background(), &protobuf.CalcRequest{
		A:  1,
		B:  2,
		Op: "+",
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(resp.GetR()) // 3

	resp, err = c.Calc(context.Background(), &protobuf.CalcRequest{
		A:  1,
		B:  0,
		Op: "/",
	})
	if err != nil { // 如果有error, 說明此次調用不成功, 作相應處理
		fmt.Println(err) // rpc error: code = Unknown desc = divided by zero
		return
	}
	fmt.Println(resp.GetR())
}

運行結果

開兩個cmd窗口, 一個進到server目錄, 執行go run server.go來啓動rpc服務.
一個進到client目錄, 執行go run client.go, 效果如下圖:
server_client

資源下載

上述示例可在這裏下載.

參考

https://grpc.io/docs/quickstart/go/
https://developers.google.com/protocol-buffers/docs/proto3

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章