1. 程式人生 > 實用技巧 >go grpc的入門使用

go grpc的入門使用

簡介

什麼是grpc

grpc是一個由google推出的、高效能、開源、通用的rpc框架。它是基於HTTP2協議標準設計開發,預設採用Protocol Buffers資料序列化協議,支援多種開發語言。

什麼是protobuf buffers

ProtoBuf buffer 是一種資料表達方式,以.proto結尾的資料檔案,可以類比json、xml等。針對ProtoBuf buffer 資料來源,可以利用protoc 工具來生成各種語言的訪問類。其操作步驟:

  1. 定義資料元;
  2. 生成資料元的訪問類。

優點:

  • 編解碼速度更快;
  • 傳輸的資料更小。

protobuf buffers定義資料元的語法

一個.proto檔案,主要包括以下部分:

syntax = "proto3";
package studentpb;
service Student {
     rpc add (StudentReqs) returns (StudentReply) {} //新增學生介面
}

message StudentReqs {
    repeated StudentReq s = 1;
}

message StudentReq{
    string name= 1;
    int32 age = 2;
}

message StudentReply {
    int32 errno = 1;
    string errmsg = 2;
}
  • 關鍵字syntax:指定使用的proto3語法;
  • 關鍵字package:定義一個包,需要注意避免命名衝突;
  • 關鍵字message來定義請求或相應需要使用的訊息格式,裡面可以包含了不同型別的欄位 。一個.proto檔案中,可以包含多個message的定義。
  • 關鍵字server來定一個服務。GRPC的服務是通過引數和返回型別來指定可以遠端呼叫的方法。

欄位的約束規則

  • repeated:前置repeated關鍵詞,宣告該欄位為陣列型別。
  • proto3不支援proto2中的required和optional關鍵字。

欄位支援的型別

支援基礎型別、列舉型別、map型別、陣列型別、message型別等。

  • 基礎型別
  • 列舉型別
syntax = "proto3";

message Student{
  string name = 1;
  // 定義enum型別
  enum Sex {
    BOY = 0;
    GIRL = 1;
  }
  Sex sex = 1; // 使用Corpus作為欄位型別
}
  • message型別
syntax = "proto3";

message Students {
    repeated Student s = 1;
}

message Student{
  string name = 1;
  // 定義enum型別
  enum Sex {
    BOY = 0;
    GIRL = 1;
  }
  Sex sex = 4; // 使用Corpus作為欄位型別
}

如何利用protoc 工具生成訪問類

prooc常用引數

案例


其中“t.proto”內容如下:

syntax = "proto3";
package studentpb;
service Student {
     rpc add (StudentReqs) returns (StudentReply) {} //新增學生介面
}

message StudentReqs {
    repeated StudentReq s = 1;
}

message StudentReq{
    string name= 1;
    int32 age = 2;
}

message StudentReply {
    int32 errno = 1;
    string errmsg = 2;
}

生成go訪問類的語句如下:

 protoc --go_out=plugins=grpc:. protobuf/*.proto

GO如何利用GRPC通訊

pb檔案

syntax = "proto3";
package studentpb;
service Student {
     rpc add (StudentReqs) returns (StudentReply) {} //新增學生介面
}

message StudentReqs {
    repeated StudentReq s = 1;
}

message StudentReq{
    string name= 1;
    int32 age = 2;
}

message StudentReply {
    int32 errno = 1;
    string errmsg = 2;
}

執行如下命令,生成grpc訪問類

protoc --go_out=plugins=grpc:. *.proto

服務端

目錄結構如下:

main.go內容如下:

package main

import (
   "context"
   "fmt"
   "google.golang.org/grpc"
   "log"
   "net"
   "test/studentpb"
)

type Student struct {
}

// 新增students
func (r *Student) Add(ctx context.Context, in *studentpb.StudentReqs) (*studentpb.StudentReply, error) {
   return &studentpb.StudentReply{
      Errno:  0,
      Errmsg: "ok",
   }, nil
}

func main() {
   // 建立server監聽
   rpcAddr := "127.0.0.1:8601"
   server, err := net.Listen("tcp", rpcAddr)
   if err != nil {
      fmt.Println("failed to listen", rpcAddr)
      panic(err)
   }

   // 建立rpc server
   var RpcServer = grpc.NewServer()
   err = RpcServer.Serve(server)
   if err != nil {
      log.Fatalf("failed to listen: %v", err)
   }

   // 對外提供服務
   r := new(Student)
   studentpb.RegisterStudentServer(RpcServer, r)
   
   select {
   }
}

使用者端

使用者端的目錄結構和服務端一樣。main.go的內容如下:

package main

import (
   "context"
   "fmt"
   "google.golang.org/grpc"
   "test/studentpb"
   "time"
)

func main() {
   addr := "127.0.0.1:8601"
   timeout := 10

   //建立rpc通道
   client, err := grpc.Dial(addr, grpc.WithInsecure())
   if err != nil {
      panic("連線失敗")
   }
   defer client.Close()

   // 建立studentrpc物件
   rpcClient := studentpb.NewStudentClient(client)

   // 建立上線文
   ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
   defer cancel()

   //封裝請求引數
   req := &studentpb.StudentReqs{}
   req.S = append(req.S, &studentpb.StudentReq{Name:"張三", Age:12})

   // 列印結果
   res , err := rpcClient.Add(ctx, req)
   if err != nil {
      fmt.Println("請求錯誤", err)
   } else {
      fmt.Println(res.GetErrno(), res.GetErrmsg())
   }
}