grpc C++异步调用的例子

代码主要是基于grpc官方examples/cpp/helloworld项目改的, 对helloworld的做了改进,可以方便的增加多个rpc调用接口

关于增加rpc接口的方法做如下介绍:

    1. 修改proto文件,增加新接口 如增加新接口 在Greeter里面增加 rpc UploadPlateIn(PlateInRequest) returns (PlateInReply) {}

并增加PlateInRequest 和 PlateInReply数据

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  rpc UploadPlateIn(PlateInRequest) returns (PlateInReply) {}
}

enum PlateType {
  TEMPORARY = 0;
  MONTHLY_PAYMENT = 1;
  OTHER_TYPE = 2;
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

message PlateInRequest {
  string plate = 1;
}
message PlateInReply {
  string     plate = 1;
  PlateType  plate_type = 2;
}

2. 这里我吧官方例子中greeter_async_server.cc中的CallData改成了模版函数,并且该模版函数继承自CallDataBase接口类(为了暴露接口Proceed() 方便处理不同rpc接口的处理函数的调用)

greeter_async_server.h的代码如下:

#include <memory>
#include <iostream>
#include <string>
#include <thread>

#include <grpcpp/grpcpp.h>
#include <grpc/support/log.h>

#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif

using grpc::Server;
using grpc::ServerAsyncResponseWriter;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::ServerCompletionQueue;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;

using helloworld::PlateInRequest;
using helloworld::PlateInReply;

class ServerImpl final {
  public:
    ~ServerImpl() {
      server_->Shutdown();
      // Always shutdown the completion queue after the server.
      cq_->Shutdown();
    }

    // There is no shutdown handling in this code.
    void Run();

 private:
    // This can be run in multiple threads if needed.
    void HandleRpcs();

    std::unique_ptr<ServerCompletionQueue> cq_;
    Greeter::AsyncService service_;
    std::unique_ptr<Server> server_;
};

class CallDataBase
{
  public:
    virtual void Proceed() = 0;
    virtual ~CallDataBase() {}
};
// Class encompasing the state and logic needed to serve a request.
template<class req, class rep>
class CallData : public CallDataBase
{
  public:
    // Take in the "service" instance (in this case representing an asynchronous
    // server) and the completion queue "cq" used for asynchronous communication
    // with the gRPC runtime.
    CallData(Greeter::AsyncService* service, ServerCompletionQueue* cq)
        : service_(service), cq_(cq), responder_(&ctx_), status_(CR
C++中实现gRPC异步调用,需要使用gRPC提供的异步接口。gRPC C++库支持多种异步调用模式,其中最常见的是基于Completion Queue(完成队列)的异步调用模型。这种模型允许开发者以非阻塞的方式处理请求和响应。 ### 异步调用的基本流程 1. **创建Stub**:首先需要通过gRPC生成的Stub来发起RPC调用。 2. **准备请求对象**:构造请求参数。 3. **发起异步调用**:使用Stub的异步方法,并传入请求对象、响应对象、以及一个回调函数或状态机来处理结果。 4. **处理响应**:当服务端返回结果后,通过回调函数或状态机处理响应数据。 ### 示例代码 以下是一个简单的示例,展示了如何使用gRPC C++实现异步调用: ```cpp #include <grpcpp/grpcpp.h> #include "helloworld.grpc.pb.h" // 生成的头文件 using grpc::Channel; using grpc::ClientAsyncResponseReader; using grpc::ClientContext; using grpc::CompletionQueue; using grpc::Status; using helloworld::HelloRequest; using helloworld::HelloReply; using helloworld::Greeter; class GreeterClient { public: explicit GreeterClient(std::shared_ptr<Channel> channel) : stub_(Greeter::NewStub(channel)) {} void SayHello(const std::string& user) { // 创建请求对象 HelloRequest request; request.set_name(user); // 创建ClientContext对象 ClientContext context; // 创建CompletionQueue对象 CompletionQueue cq; // 创建响应对象 HelloReply reply; // 创建异步调用对象 std::unique_ptr<ClientAsyncResponseReader<HelloReply>> rpc( stub_->PrepareAsyncSayHello(&context, request, &cq)); // 开始异步调用 rpc->StartCall(); // 设置响应处理回调 rpc->Finish(&reply, &status_, [this, &cq](bool ok) { if (ok && status_.ok()) { std::cout << "Reply: " << reply.message() << std::endl; } else { std::cout << "RPC failed" << std::endl; } // 通知CompletionQueue处理完成 cq.Shutdown(); }); // 等待异步调用完成 void* got_tag; bool ok = false; GPR_ASSERT(cq.Next(&got_tag, &ok)); GPR_ASSERT(ok); } private: std::unique_ptr<Greeter::Stub> stub_; Status status_; }; int main(int argc, char** argv) { GreeterClient client(grpc::CreateChannel( "localhost:50051", grpc::InsecureChannelCredentials())); client.SayHello("world"); return 0; } ``` ### 关键点说明 - **ClientContext**:用于传递请求上下文信息,如超时、元数据等。 - **CompletionQueue**:用于管理异步操作的结果。每个异步调用都会将结果放入这个队列中。 - **ClientAsyncResponseReader**:用于读取异步调用的结果。它提供了`Finish`方法来获取最终的响应对象和状态。 - **Finish**:该方法用于获取最终的响应对象和状态,并设置一个回调函数来处理结果。 ### 异步调用的优势 - **非阻塞**:异步调用不会阻塞主线程,适合处理高并发场景。 - **资源利用率高**:通过Completion Queue机制,可以高效地管理和调度多个异步操作。 - **灵活性**:可以通过回调函数或状态机来处理不同的异步操作结果。 ### 总结 在C++中实现gRPC异步调用,主要依赖于gRPC提供的Completion Queue和ClientAsyncResponseReader接口。通过这些接口,可以实现高效的非阻塞通信,适用于需要高性能和高并发的应用场景。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值