前言
grpc是一個高性能、通用的開源RPC框架,基于HTTP/2協(xié)議標(biāo)準(zhǔn)和Protobuf序列化協(xié)議開發(fā),支持眾多的開發(fā)語言。在對接口具有嚴(yán)格約束或者傳遞大量數(shù)據(jù)的場景中得到了廣泛的應(yīng)用。本文作者從什么是grpc開始介紹,講訴了protobuf的語法以及如何使用grpc框架,對于想學(xué)習(xí)grpc的初學(xué)者來說,是一篇極好的入門教程,下來就跟隨作者一起學(xué)習(xí)吧。
簡介
什么是grpc
grpc是一個由google推出的、高性能、開源、通用的rpc框架。它是基于HTTP2協(xié)議標(biāo)準(zhǔn)設(shè)計開發(fā),默認(rèn)采用Protocol Buffers數(shù)據(jù)序列化協(xié)議,支持多種開發(fā)語言。
什么是protobuf buffers
ProtoBuf buffer 是一種數(shù)據(jù)表達(dá)方式,以.proto結(jié)尾的數(shù)據(jù)文件,可以類比json、xml等。針對ProtoBuf buffer 數(shù)據(jù)源,可以利用protoc 工具來生成各種語言的訪問類。
其操作步驟:
- 定義數(shù)據(jù)元;
- 生成數(shù)據(jù)元的訪問類。
優(yōu)點:
- 編解碼速度更快;
- 傳輸?shù)臄?shù)據(jù)更小。
protobuf buffers定義數(shù)據(jù)元的語法
一個.proto文件,主要包括以下部分:
syntax = "proto3";package studentpb;service Student { rpc add (StudentReqs) returns (StudentReply) {} //新增學(xué)生接口}message StudentReqs { repeated StudentReq s = 1;}message StudentReq{ string name= 1; int32 age = 2;}message StudentReply { int32 errno = 1; string errmsg = 2;}
- 關(guān)鍵字syntax:指定使用的proto3語法;
- 關(guān)鍵字package:定義一個包,需要注意避免命名沖突;
- 關(guān)鍵字message來定義請求或相應(yīng)需要使用的消息格式,里面可以包含了不同類型的字段 。一個.proto文件中,可以包含多個message的定義。
- 關(guān)鍵字server來定一個服務(wù)。GRPC的服務(wù)是通過參數(shù)和返回類型來指定可以遠(yuǎn)程調(diào)用的方法。
字段的約束規(guī)則
- repeated:前置repeated關(guān)鍵詞,聲明該字段為數(shù)組類型。
- proto3不支持proto2中的required和optional關(guān)鍵字。
字段支持的類型
支持基礎(chǔ)類型、枚舉類型、map類型、數(shù)組類型、message類型等。
- 基礎(chǔ)類型

- 枚舉類型
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常用參數(shù)

案例
文件目錄如下:

其中“t.proto”內(nèi)容如下:
syntax = "proto3";package studentpb;service Student { rpc add (StudentReqs) returns (StudentReply) {} //新增學(xué)生接口}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) {} //新增學(xué)生接口}message StudentReqs { repeated StudentReq s = 1;}message StudentReq{ string name= 1; int32 age = 2;}message StudentReply { int32 errno = 1; string errmsg = 2;}
執(zhí)行如下命令,生成grpc訪問類
protoc --go_out=plugins=grpc:. *.proto
服務(wù)端
目錄結(jié)構(gòu)如下:

main.go內(nèi)容如下:
package mainimport ( "context" "fmt" "google.golang.org/grpc" "log" "net" "test/studentpb")type Student struct {}// 新增studentsfunc (r *Student) Add(ctx context.Context, in *studentpb.StudentReqs) (*studentpb.StudentReply, error) { return &studentpb.StudentReply{ Errno: 0, Errmsg: "ok", }, nil}func main() { // 建立server監(jiān)聽 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) } // 對外提供服務(wù) r := new(Student) studentpb.RegisterStudentServer(RpcServer, r) select { }}
用戶端
目錄結(jié)構(gòu)如下:
package mainimport ( "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() // 創(chuàng)建studentrpc對象 rpcClient := studentpb.NewStudentClient(client) // 創(chuàng)建上線文 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second) defer cancel() //封裝請求參數(shù) req := &studentpb.StudentReqs{} req.S = Append(req.S, &studentpb.StudentReq{Name:"張三", Age:12}) // 打印結(jié)果 res , err := rpcClient.Add(ctx, req) if err != nil { fmt.Println("請求錯誤", err) } else { fmt.Println(res.GetErrno(), res.GetErrmsg()) }}
關(guān)于360技術(shù):360技術(shù)是360技術(shù)團(tuán)隊打造的技術(shù)分享公眾號,每天推送技術(shù)干貨內(nèi)容,更多技術(shù)信息歡迎關(guān)注“360技術(shù)”微信公眾號