RPC 編程 -三-:gRPC 快速入門
- 什麼是 gRPC
gRPC 是一個高性能、開源、通用的RPC
框架,由Google
推出,基於 HTTP2 協議標準設計開發,默認採用 Protocol Buffers 數據序列化協議,支持多種開發語言。gRPC
提供了一種簡單的方法來精確的定義服務,並且爲客戶端和服務端自動生成可靠的功能庫。
2.gRPC 技術棧
最底層爲
TCP
或Unix
套接字協議,在此之上是HTTP/2
協議的實現,然後在HTTP/2
協議之上又構建了針對Go
語言的gRPC
核心庫(gRPC
內核 + 解釋器)。應用程序通過gRPC
插件生成的Stub
代碼和gRPC
核心庫通信,也可以直接和gRPC
核心庫通信。
- 前置準備
3.1 安裝protoc
下面示例是在
mac環境
中安裝。
# 安裝
➜ brew install protobuf
# 查看安裝後版本
➜ protoc --version
libprotoc 3.17.3
3.2 安裝插件
安裝插件的目的是爲了將
protobuf
文件,生成Go
代碼
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
3.3 設置插件環境變量
$ export PATH="$PATH:$(go env GOPATH)/bin"
3.4 驗證插件是否成功
# 查看protoc-gen-go版本
$ protoc-gen-go --version
protoc-gen-go v1.26.0
# 查看protoc-gen-go-grpc版本
$ protoc-gen-go-grpc --version
protoc-gen-go-grpc 1.1.0
- 快速使用
4.1 定義protobuf
文件
文件名: hello.proto
syntax = "proto3";
package hello;
// 定義go生成後的包名
option go_package = "server/hello";
// 定義入參
message Request {
string name =1;
}
// 定義返回
message Response {
string result = 1;
}
// 定義接口
service UserService {
rpc Say(Request) returns (Response);
}
4.2 生成GO
代碼
# 同時生成hello.pb.go 和 hello_grpc.pb.go
$ protoc --go-grpc_out=. --go_out=. hello.proto
4.3 查看生成代碼
1. hello.pb.go
部分代碼
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.17.3
// source: grpc/hello.proto
package hello
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// 定義入參
type Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,`
}
func (x *Request) GetName() string {
if x != nil {
return x.Name
}
return ""
}
// 定義返回
type Response struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Result string `protobuf:"bytes,1,opt,`
}
func (x *Response) GetResult() string {
if x != nil {
return x.Result
}
return ""
}
2. hello_grpc.pb.go
部分代碼
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package hello
import (
context "context"
"fmt"
grpc "google.golang.org/grpc"
)
// ---------- 客戶端相關代碼 --------
// 客戶端接口
type UserServiceClient interface {
Say(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
}
// 實現客戶端接口
type userServiceClient struct {
cc grpc.ClientConnInterface
}
// 實例化客戶端
func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient {
return &userServiceClient{cc}
}
// 客戶端調用Say方法
func (c *userServiceClient) Say(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
out := new(Response)
err := c.cc.Invoke(ctx, "/hello.UserService/Say", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ---------- 服務端相關代碼 ------------------
// 定義服務端接口
type UserServiceServer interface {
Say(context.Context, *Request) (*Response, error)
mustEmbedUnimplementedUserServiceServer()
}
// 實現服務端接口
type UnimplementedUserServiceServer struct {
}
// 實現方法
func (UnimplementedUserServiceServer) Say(ctx context.Context, r *Request) (*Response, error) {
// 自己編寫代碼
reply := &Response{
Result: fmt.Sprintf("%s say hello word!", r.Name),
}
return reply, nil
}
// 註冊服務
func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) {
s.RegisterService(&UserService_ServiceDesc, srv)
}
4.4 下載grpc
包
$ go get -u google.golang.org/grpc
4.5 編寫服務端代碼
server.go
package main
import (
"52lu/go-study-example/grpc/server/hello"
"fmt"
"google.golang.org/grpc"
"net"
)
func main() {
// 創建grpc服務
grpcServer := grpc.NewServer()
// 註冊服務
hello.RegisterUserServiceServer(grpcServer, new(hello.UnimplementedUserServiceServer))
// 監聽端口
listen, err := net.Listen("tcp", ":1234")
if err != nil {
fmt.Println("服務啓動失敗", err)
return
}
grpcServer.Serve(listen)
}
4.6 編寫客戶端代碼
client.go
package main
import (
"52lu/go-study-example/grpc/server/hello"
"fmt"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
func main() {
// 建立鏈接
conn, err := grpc.Dial("127.0.0.1:1234", grpc.WithInsecure())
if err != nil {
fmt.Println("Dial Error ", err)
return
}
// 延遲關閉鏈接
defer conn.Close()
// 實例化客戶端
client := hello.NewUserServiceClient(conn)
// 發起請求
reply, err := client.Say(context.TODO(), &hello.Request{Name: "張三"})
if err != nil {
return
}
fmt.Println("返回:", reply.Result)
}
4.7 啓動 & 請求
# 啓動服務端
$ go run server.go
# 啓動客戶端
$ go run client.go
返回: 張三 say hello word!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/mLEVmomeN-Vd1aFGX7gZug