gRPC 基本使用

gRPC 基本使用

gRPC 是一个高性能、开源且通用的远程过程调用 (RPC) 框架,它能够让你从客户端轻松地调用另一台机器上的服务端方法,就像调用本地对象一样,同时为你管理了很多细节,如线程管理和网络传输等。gRPC 支持多种语言,并且默认使用 Protocol Buffers 作为接口定义语言(IDL)来定义服务接口以及消息格式。

下面是 gRPC 的基本使用步骤:

1、定义服务接口

首先使用 protobuf 语言定义服务接口,定义在以 .proto 结尾的文件中,其中包含了服务的名称、服务的方法以及每个方法的消息格式。

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
// 指定使用的 Protocol Buffers 版本为 proto3。
syntax = "proto3";

// 定义了一个名为 `example` 的包。所有的消息和服务都属于这个包。相当于C++的命名空间
package example;

// 定义了一个名为 `Echo` 的服务。
// 服务定义了可以被远程调用的方法。
service Echo {
// `SayHello` 是一个远程过程调用方法。
// 它接收一个 `HelloRequest` 类型的消息作为参数,
// 并返回一个 `HelloResponse` 类型的消息。
rpc SayHello (HelloRequest) returns (HelloResponse);
}

// 定义了一个名为 `HelloRequest` 的消息类型。
// 这个消息有一个字段 `greeting`,类型为 `string`。
// 字段的序号为 1,这意味着在序列化过程中,它会被编码为第一个字段。
message HelloRequest {
string greeting = 1; // 请求消息体中的字符串字段
}

// 定义了一个名为 `HelloResponse` 的消息类型。
// 这个消息有一个字段 `reply`,类型为 `string`。
// 字段的序号为 1,这意味着在序列化过程中,它会被编码为第一个字段。
message HelloResponse {
string reply = 1; // 响应消息体中的字符串字段
}

2、生成代码

使用 Protocol Buffers 编译器 (protoc) 和相应语言对应的 gRPC 插件生成客户端和服务器端的存根代码。

1
2
3
4
// 生成 c++ 消息类: echo.pb.h echo.pb.cc
protoc -I=. --cpp_out=. echo.proto
// 生成 gRPC 存根代码: echo.grpc.pb.h ehco.grpc.pb.cc
protoc -I=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` echo.proto

protoc 命令解析

-I:指定 .proto 文件的搜索路径

--cpp_out:指定生成 C++ 代码的输出路径

--grpc_out:指定生成 gRPC 存根代码的输出路径

--plugin=proto-gen-grpc='which grpc_cpp_plugin':指定要使用的插件

3、实现服务

继承自动生成的服务类并实现其中的虚函数。

1
2
3
4
5
6
7
8
9
class EchoServiceImpl final : public example::Echo::Service {
public:
grpc::Status SayHello(grpc::ServerContext* context, const example::HelloRequest* request,
example::HelloResponse* reply) override {
std::string prefix("Hello ");
reply->set_reply(prefix + request->greeting());
return grpc::Status::OK;
}
};

4、创建服务器

创建一个 gRPC 服务实例,并将实现的服务注册到服务器上。

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
#include <iostream>
#include <memory>

// 导入 gRPC 相关头文件
#include <grpcpp/grpcpp.h>
#include "example.pb.h" // 自动生成的消息头文件
#include "example.grpc.pb.h" // 自动生成的服务头文件

// 主函数
int main(int argc, char** argv) {
// 服务器监听地址
std::string server_address("0.0.0.0:50051");

// 创建服务实例
EchoServiceImpl service;

// 创建 ServerBuilder 对象
grpc::ServerBuilder builder;

// 添加监听端口
// 使用不安全的凭证(仅适用于开发环境)
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());

// 注册服务
// 将服务实例注册到 ServerBuilder 中
builder.RegisterService(&service);

// 构建并启动服务器
// BuildAndStart() 方法返回一个 unique_ptr 指向 Server 对象
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());

// 输出服务器监听地址
std::cout << "Server listening on " << server_address << std::endl;

// 等待服务器关闭
// 这里阻塞主线程,等待服务器关闭
server->Wait();

return 0;
}

5、创建客户端

创建一个客户端实例连接到 gRPC 服务器,并调用服务的方法。

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
41
42
#include <iostream>
#include <memory>

// 导入 gRPC 相关头文件
#include <grpcpp/grpcpp.h>
#include "example.pb.h" // 自动生成的消息头文件
#include "example.grpc.pb.h" // 自动生成的服务头文件

int main() {
// 创建一个 gRPC 通道
// 通道用于与远程服务器通信
std::shared_ptr<grpc::Channel> channel = grpc::CreateChannel(
"localhost:50051", grpc::InsecureChannelCredentials());

// 创建服务存根
// 存根用于发起 RPC 调用
std::unique_ptr<example::Echo::Stub> stub = example::Echo::NewStub(channel);

// 创建请求消息
example::HelloRequest request;
request.set_greeting("world");

// 创建响应消息
example::HelloResponse reply;

// 创建客户端上下文
// 用于传递额外的信息,如元数据、截止时间等
grpc::ClientContext context;

// 发起 RPC 调用
// SayHello 方法接收请求消息并返回响应消息
grpc::Status status = stub->SayHello(&context, request, &reply);

// 检查 RPC 调用的状态
if (status.ok()) {
std::cout << "Greeter received: " << reply.reply() << std::endl;
} else {
std::cout << "Greeter RPC failed: " << status.error_code() << ": " << status.error_message() << std::endl;
}

return 0;
}

gRPC 基本使用
https://linhanmic.github.io/2024/09/26/gRPC基本使用/
作者
Linhanmic
发布于
2024年9月26日
更新于
2024年9月26日
许可协议