c++ gRPC框架怎么用 c++微服务通信入门【教程】

用C++写gRPC微服务核心三步:定义.proto接口、生成C++代码、实现服务端与客户端;需注意环境配置、proto语法规范、代码生成及链接gRPC库等细节。

用 C++ 写 gRPC 微服务,核心就三步:定义接口(.proto)、生成 C++ 代码、实现服务端和客户端。不复杂,但容易卡在环境配置和编译细节上。

1. 安装 gRPC 和 Protocol Buffers

推荐用 预编译二进制 + CMake 导入 方式,避开源码编译的坑:

  • 从 gRPC GitHub Releases 下载对应系统的 grpc-cpp 预编译包(含 protobuf)
  • 解压后把 include/lib/ 路径记下来,CMakeLists.txt 中用 find_package(gRPC CONFIG) 或手动 include_directories() + target_link_libraries()
  • 确保 protoc(protobuf 编译器)在 PATH 中,版本建议 ≥ 3.20(与 gRPC v1.50+ 兼容)

2. 写 .proto 文件定义服务

这是通信契约,必须清晰简洁。例如定义一个用户查询服务:

syntax = "proto3";
package user;

service UserService { rpc GetUser (UserRequest) returns (UserResponse); }

message UserRequest { int32 id = 1; }

message UserResponse { int32 id = 1; string name = 2; bool found = 3; }

注意:别漏写 syntax = "proto3"package 影响生成的 C++ 命名空间;字段编号不能重复,且尽量从 1 开始紧凑编号。

立即学习“C++免费学习笔记(深入)”;

3. 生成 C++ 代码并编译

用 protoc 命令一键生成:

protoc -I=. --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` user.proto

会生成 user.pb.h/.cc(数据结构)和 user.grpc.pb.h/.cc(服务桩)两个头文件+源文件。CMake 中记得把它们加入 add_library()add_executable() 的源列表,并链接 gpr;grpc;grpc++ 等库。

4. 实现服务端和客户端

服务端:继承生成的基类,重写 RPC 方法,启动 ServerBuilder:

class UserServiceImpl final : public user::UserService::Service {
 public:
  Status GetUser(ServerContext* ctx, const UserRequest* req,
                 UserResponse* resp) override {
    resp->set_id(req->id());
    resp->set_name("Alice");
    resp->set_found(true);
    return Status::OK;
  }
};

// 启动 ServerBuilder builder; builder.AddListeningPort("0.0.0.0:50051", grpc::InsecureServerCredentials()); builder.RegisterService(new UserServiceImpl()); std::unique_ptr server(builder.BuildAndStart()); server->Wait();

客户端:用生成的 stub 调用:

auto channel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials());
auto stub = user::UserService::NewStub(channel);

ClientContext context; UserRequest req; req.set_id(123); UserResponse resp; Status status = stub->GetUser(&context, req, &resp); if (status.ok()) { std::cout << "Name: " << resp.name() << "\n"; }

关键点:客户端 channel 是线程安全的,可复用;服务端每个 RPC 在独立线程中执行,默认并发处理;错误用 Status 判断,不是异常抛出。