gRPC for C++ 实战全流程 —— 从零搭建到同步/异步服务


1. gRPC 项目流程概览

gRPC 在 C++ 中的开发流程可以用以下步骤概括:

  1. 编写 proto 文件
  2. 生成 C++ 源码(包含 Protobuf 序列化代码和 gRPC 服务框架代码)
  3. 实现 gRPC Server 端(继承并重写 Service 接口)
  4. 实现 gRPC Client 端(通过 Stub 调用服务)
  5. 编译运行
  6. (可选)实现异步 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,重写 RegistLogin 方法。

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 一个类封装多个接口

  • 优点:代码集中
  • 缺点:所有接口的成员变量都会被初始化,占用内存

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值