grpc学习
yatbfm

介绍

gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。

安装

gRPC 基于 ProtoBuf 序列化协议,因此需要安装 protoc 编译器用于编译 protocolbuf(.proto 文件)和 protobuf 运行时。

下载 protoc

进入protobuf 仓库下载预编译好的 protoc 二进制文件。 我这里是 windows 环境,因此选择 win 的版本下载。 下载完成后,解压到自己的相关目录即可。然后配置环境变量。 然后执行命令protoc --version,输出对应版本表示安装成功。image-20240417191053951.png

下载 go plugins

安装好 protoc 编译器后,还需要安装相关语言的插件,比如这里使用 go 语言,需要安装 go 语言的插件,插件会将编译后的结果生成为 go 代码供我们使用。 可以直接使用 go 命令安装。

1
2
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

相关的执行文件会安装到$GOPATH/bin目录下。 还需要其他 grpc 相关的包,这里不单独安装,在运行代码时再进行安装。

DEMO

gRPC 主要有 4 种请求和响应模式,分别是简单模式(Simple RPC)、服务端流式(Server-side streaming RPC)、客户端流式(Client-side streaming RPC)、和双向流式(Bidirectional streaming RPC)。

  • 简单模式(Simple RPC):客户端发起请求并等待服务端响应。
  • 服务端流式(Server-side streaming RPC):客户端发送请求到服务器,拿到一个流去读取返回的消息序列。 客户端读取返回的流,直到里面没有任何消息。
  • 客户端流式(Client-side streaming RPC):与服务端数据流模式相反,这次是客户端源源不断的向服务端发送数据流,而在发送结束后,由服务端返回一个响应。
  • 双向流式(Bidirectional streaming RPC):双方使用读写流去发送一个消息序列,两个流独立操作,双方可以同时发送和同时接收。

简单模式

项目根目录为LearnGo,该目录下的 gRPC 相关目录结构为: image.png

定义服务

通过 protobuf 语法定义和编程语言、平台无关的接口。文件test.proto内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
syntax = "proto3";

// option go_package = "path;name";
// path 表示生成的go文件的存放地址,如果目录不存在会自动生成目录
// name 表示生成的go文件所属的包名
option go_package = "./;proto";
// 定义包名
package proto;
// 定义消息
message HelloRequest {
string name = 1;
}

message HelloReply {
string message = 1;
}
// 定义服务
service Greeter {
// 定义方法,接受的HelloRequest消息,返回HelloReply消息
rpc SayHello(HelloRequest) returns (HelloReply) {}
}

编译

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative test.proto 编译完成后,会生成一个test.pb.gotest_grpc.pb.go文件。 我使用的Intellij IDEA打开的项目,进入到生成的文件中,会报错提示找不到包,可以直接使用 IDE 安装相关包即可。 每次编译都需要执行命令可能会很麻烦,可以在 IDEA 中定义工具菜单,简化操作。 首先打开设置菜单 image.png 添加工具, image.png 按照自己的指令进行设置即可。 --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative $FileName$ 然后选中xxx.proto文件,找到External Tools选择即可。

服务端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package main

import (
// 自己编写的proto文件生成的包
pb "LearnGo/test05/proto"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"log"
"net"
)
// 定义server,用来实现proto文件里实现的接口
type server struct{
pb.UnimplementedGreeterServer
}
// 实现定义的SayHello接口
// 第一个是上下文参数,默认要填;第二个是定义的HelloRequest消息
// 返回值是我们定义的HelloReply消息,error返回值也是必须的。
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("receive the message: %v", in.Name)
return &pb.HelloReply{Message: in.Name}, nil
}

func main() {
// 设定监听端口
lis, err := net.Listen("tcp", "127.0.0.1:50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// 实例化gRPC服务器
s := grpc.NewServer()
// 注册服务
pb.RegisterGreeterServer(s, &server{})
// 向gRPC服务端注册反射服务
reflection.Register(s)
// 启动服务
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}

客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
// 导入生成的proto包
"LearnGo/test05/proto"
"context"
"google.golang.org/grpc"
"log"
"time"
)

func main() {
// 连接grpc服务器
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
log.Fatalf("filed to connect: %v", err)
}
// 延迟关闭连接
defer conn.Close()
// 新建Greeter服务 客户端
c := proto.NewGreeterClient(conn)
// 初始化上下文,设置请求超时为1秒
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
// 延迟关闭会话
defer cancel()
// 调用SayHello接口发送消息
reply, err := c.SayHello(ctx, &proto.HelloRequest{Name: "test grpc"})
if err != nil {
log.Fatalf("failed to send: %v", err)
}
// 打印服务的返回消息
log.Printf("the reply message: %v", reply.Message)
}

执行

分别执行server.goclient.go程序,可以看到打印的结果 服务端打印:image.png 客户端打印:image.png

由 Hexo 驱动 & 主题 Keep
访客数 访问量