gRPC C++ — RPC 框架
gRPC 是 Google 开源的高性能 RPC 框架,基于 HTTP/2 和 Protocol Buffers,是微服务通信的标准选择。
安装
bash
# vcpkg
vcpkg install grpc protobuf
# CMake
find_package(gRPC REQUIRED)
find_package(Protobuf REQUIRED)
target_link_libraries(myapp PRIVATE gRPC::grpc++ protobuf::libprotobuf)定义服务(Proto)
protobuf
// user.proto
syntax = "proto3";
package user;
service UserService {
rpc GetUser (GetUserRequest) returns (UserResponse);
rpc CreateUser (CreateUserRequest) returns (UserResponse);
rpc ListUsers (ListUsersRequest) returns (stream UserResponse); // 服务端流
rpc Chat (stream ChatMessage) returns (stream ChatMessage); // 双向流
}
message GetUserRequest { int32 id = 1; }
message CreateUserRequest {
string name = 1;
int32 age = 2;
string email = 3;
}
message UserResponse {
int32 id = 1;
string name = 2;
int32 age = 3;
string email = 4;
}
message ListUsersRequest { int32 page = 1; int32 limit = 2; }
message ChatMessage { string user = 1; string text = 2; }bash
# 生成 C++ 代码
protoc --cpp_out=. --grpc_out=. \
--plugin=protoc-gen-grpc=`which grpc_cpp_plugin` \
user.proto
# 生成:user.pb.h user.pb.cc user.grpc.pb.h user.grpc.pb.cc服务端实现
cpp
#include <grpcpp/grpcpp.h>
#include "user.grpc.pb.h"
class UserServiceImpl final : public user::UserService::Service {
public:
// 一元 RPC
grpc::Status GetUser(grpc::ServerContext* ctx,
const user::GetUserRequest* req,
user::UserResponse* resp) override {
int id = req->id();
// 查询数据库...
resp->set_id(id);
resp->set_name("Alice");
resp->set_age(30);
resp->set_email("alice@example.com");
return grpc::Status::OK;
}
// 服务端流式 RPC
grpc::Status ListUsers(grpc::ServerContext* ctx,
const user::ListUsersRequest* req,
grpc::ServerWriter<user::UserResponse>* writer) override {
for (int i = 0; i < req->limit(); ++i) {
user::UserResponse u;
u.set_id(i + 1);
u.set_name("User " + std::to_string(i + 1));
writer->Write(u); // 流式写入
}
return grpc::Status::OK;
}
// 双向流式 RPC
grpc::Status Chat(grpc::ServerContext* ctx,
grpc::ServerReaderWriter<user::ChatMessage,
user::ChatMessage>* stream) override {
user::ChatMessage msg;
while (stream->Read(&msg)) {
user::ChatMessage reply;
reply.set_user("server");
reply.set_text("Echo: " + msg.text());
stream->Write(reply);
}
return grpc::Status::OK;
}
};
void RunServer() {
std::string addr = "0.0.0.0:50051";
UserServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(addr, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
// 性能调优
builder.SetMaxReceiveMessageSize(16 * 1024 * 1024); // 16MB
builder.SetMaxSendMessageSize(16 * 1024 * 1024);
auto server = builder.BuildAndStart();
std::cout << "gRPC 服务器启动: " << addr << "\n";
server->Wait();
}客户端
cpp
#include <grpcpp/grpcpp.h>
#include "user.grpc.pb.h"
class UserClient {
std::unique_ptr<user::UserService::Stub> stub_;
public:
explicit UserClient(std::shared_ptr<grpc::Channel> channel)
: stub_(user::UserService::NewStub(channel)) {}
// 一元调用
std::optional<user::UserResponse> GetUser(int id) {
user::GetUserRequest req;
req.set_id(id);
user::UserResponse resp;
grpc::ClientContext ctx;
ctx.set_deadline(std::chrono::system_clock::now() +
std::chrono::seconds(5)); // 超时
auto status = stub_->GetUser(&ctx, req, &resp);
if (status.ok()) return resp;
std::cerr << "RPC 失败: " << status.error_message() << "\n";
return std::nullopt;
}
// 服务端流
void ListUsers(int limit) {
user::ListUsersRequest req;
req.set_limit(limit);
grpc::ClientContext ctx;
auto reader = stub_->ListUsers(&ctx, req);
user::UserResponse u;
while (reader->Read(&u)) {
std::cout << u.id() << ": " << u.name() << "\n";
}
auto status = reader->Finish();
if (!status.ok()) std::cerr << "流错误: " << status.error_message() << "\n";
}
};
int main() {
auto channel = grpc::CreateChannel("localhost:50051",
grpc::InsecureChannelCredentials());
UserClient client(channel);
if (auto user = client.GetUser(1)) {
std::cout << "用户: " << user->name() << "\n";
}
client.ListUsers(10);
}TLS 安全连接
cpp
// 服务端 TLS
grpc::SslServerCredentialsOptions ssl_opts;
ssl_opts.pem_key_cert_pairs.push_back({
read_file("server.key"),
read_file("server.crt")
});
ssl_opts.pem_root_certs = read_file("ca.crt");
builder.AddListeningPort(addr, grpc::SslServerCredentials(ssl_opts));
// 客户端 TLS
grpc::SslCredentialsOptions ssl_opts;
ssl_opts.pem_root_certs = read_file("ca.crt");
ssl_opts.pem_private_key = read_file("client.key");
ssl_opts.pem_cert_chain = read_file("client.crt");
auto channel = grpc::CreateChannel("localhost:50051",
grpc::SslCredentials(ssl_opts));拦截器(Interceptor)
cpp
// 日志拦截器
class LoggingInterceptor : public grpc::experimental::Interceptor {
public:
void Intercept(grpc::experimental::InterceptorBatchMethods* methods) override {
if (methods->QueryInterceptionHookPoint(
grpc::experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
auto* meta = methods->GetSendInitialMetadata();
std::cout << "RPC 调用开始\n";
}
methods->Proceed();
}
};关键认知
gRPC 的核心优势是强类型接口 + 高效二进制序列化 + HTTP/2 多路复用。Proto 文件是服务契约,先设计好接口再实现。生产环境必须启用 TLS。流式 RPC 适合大数据传输和实时通信场景。