go grpc的入門使用
阿新 • • 發佈:2020-11-27
簡介
什麼是grpc
grpc是一個由google推出的、高效能、開源、通用的rpc框架。它是基於HTTP2協議標準設計開發,預設採用Protocol Buffers資料序列化協議,支援多種開發語言。
什麼是protobuf buffers
ProtoBuf buffer 是一種資料表達方式,以.proto結尾的資料檔案,可以類比json、xml等。針對ProtoBuf buffer 資料來源,可以利用protoc 工具來生成各種語言的訪問類。其操作步驟:
- 定義資料元;
- 生成資料元的訪問類。
優點:
- 編解碼速度更快;
- 傳輸的資料更小。
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())
}
}