gRPC for C++ 实战全流程 —— 从零搭建到同步/异步服务
目录
- 1. gRPC 项目流程概览
- 2. 编写 proto 文件
- 3. 生成 C++ 代码
- 4. 同步 gRPC Server 端
- 4.1 实现服务类
- 4.2 启动服务
- 5. 同步 gRPC Client 端
- 6. 异步 gRPC Server 端
- 6.1 每个接口封装一个子类
- 6.2 一个类封装多个接口
1. gRPC 项目流程概览
gRPC 在 C++ 中的开发流程可以用以下步骤概括:
- 编写 proto 文件
- 生成 C++ 源码(包含 Protobuf 序列化代码和 gRPC 服务框架代码)
- 实现 gRPC Server 端(继承并重写 Service 接口)
- 实现 gRPC Client 端(通过 Stub 调用服务)
- 编译运行
- (可选)实现异步 Server 端
2. 编写 proto 文件
示例 IM.Login.proto
定义了两个 RPC 接口:注册和登录。
syntax = "proto3";
package IM.Login;service ImLogin {rpc Regist (IMRegistReq) returns (IMRegistRes) {}rpc Login (IMLoginReq) returns (IMLoginRes) {}
}message IMRegistReq {string user_name = 1;string password = 2;
}message IMRegistRes {string user_name = 1;uint32 user_id = 2;uint32 result_code = 3; // 0 表示成功
}message IMLoginReq {string user_name = 1;string password = 2;
}message IMLoginRes {uint32 user_id = 1;uint32 result_code = 2; // 0 表示成功
}
3. 生成 C++ 代码
需要生成两类文件:
- Protobuf 序列化代码(
*.pb.h
/*.pb.cc
) - gRPC 服务框架代码(
*.grpc.pb.h
/*.grpc.pb.cc
)
命令示例:
protoc -I . --cpp_out=. IM.Login.proto
protoc -I . --grpc_out=. \--plugin=protoc-gen-grpc=`which grpc_cpp_plugin` \IM.Login.proto
执行后会生成:
IM.Login.pb.h / IM.Login.pb.cc
IM.Login.grpc.pb.h / IM.Login.grpc.pb.cc
4. 同步 gRPC Server 端
4.1 实现服务类
继承 ImLogin::Service
,重写 Regist
和 Login
方法。
class IMLoginServiceImpl : public ImLogin::Service {Status Regist(ServerContext* context, const IMRegistReq* request,IMRegistRes* response) override {response->set_user_name(request->user_name());response->set_user_id(10);response->set_result_code(0);return Status::OK;}Status Login(ServerContext* context, const IMLoginReq* request,IMLoginRes* response) override {response->set_user_id(10);response->set_result_code(0);return Status::OK;}
};
4.2 启动服务
void RunServer() {std::string addr("0.0.0.0:50051");IMLoginServiceImpl service;ServerBuilder builder;builder.AddListeningPort(addr, grpc::InsecureServerCredentials());builder.RegisterService(&service);auto server = builder.BuildAndStart();std::cout << "Server listening on " << addr << std::endl;server->Wait();
}
5. 同步 gRPC Client 端
class ImLoginClient {
public:ImLoginClient(std::shared_ptr<Channel> channel): stub_(ImLogin::NewStub(channel)) {}void Regist(const std::string& user, const std::string& pwd) {IMRegistReq req;req.set_user_name(user);req.set_password(pwd);IMRegistRes res;ClientContext ctx;Status status = stub_->Regist(&ctx, req, &res);if (status.ok())std::cout << "注册成功: user_id=" << res.user_id() << std::endl;}void Login(const std::string& user, const std::string& pwd) {IMLoginReq req;req.set_user_name(user);req.set_password(pwd);IMLoginRes res;ClientContext ctx;Status status = stub_->Login(&ctx, req, &res);if (status.ok())std::cout << "登录成功: user_id=" << res.user_id() << std::endl;}private:std::unique_ptr<ImLogin::Stub> stub_;
};
6. 异步 gRPC Server 端
异步服务基于 CompletionQueue 和 状态机 实现,有两种封装方式。
6.1 每个接口封装一个子类
- 优点:逻辑分离清晰
- 缺点:接口多时类文件多
每个接口一个 CallData
类,内部维护状态:
CREATE -> PROCESS -> FINISH
在 PROCESS
状态中创建新对象以处理后续请求。
6.2 一个类封装多个接口
- 优点:代码集中
- 缺点:所有接口的成员变量都会被初始化,占用内存
参考:
- 0voice · GitHub