如何在Protobuf中用C ++生成BlockingStub?

时间:2015-05-08 09:10:30

标签: c++ protocol-buffers

我有Protobuf的以下.proto(2.6.1更详细):

service InstallService {
    rpc getWifiNetworks (WifiRequest) returns (WifiResponse);
}

我已经生成了java文件,并且我有BlockingStub:

TestInstallService.BlockingInterface service = TestInstallService.newBlockingStub(channel);

我可以使用if阻塞方式(效果很好):

Wifi.WifiResponse response = service.getWifiNetworks(controller, request);

现在我正在创建C ++客户端,它也应该以阻塞方式工作,但我无法在proto和生成的C ++代码中看到任何Blocking接口。如何在Protobuf中用C ++生成BlockingStub?如果以异步方式工作,我怎么能通过关闭?

生成的C ++服务文件(.cpp):

class InstallService_Stub;

class InstallService : public ::google::protobuf::Service {
 protected:
  // This class should be treated as an abstract interface.
  inline InstallService() {};
 public:
  virtual ~InstallService();

  typedef InstallService_Stub Stub;

  static const ::google::protobuf::ServiceDescriptor* descriptor();

  virtual void getWifiNetworks(::google::protobuf::RpcController* controller,
                       const ::WifiRequest* request,
                       ::WifiResponse* response,
                       ::google::protobuf::Closure* done);

  // implements Service ----------------------------------------------

  const ::google::protobuf::ServiceDescriptor* GetDescriptor();
  void CallMethod(const ::google::protobuf::MethodDescriptor* method,
                  ::google::protobuf::RpcController* controller,
                  const ::google::protobuf::Message* request,
                  ::google::protobuf::Message* response,
                  ::google::protobuf::Closure* done);
  const ::google::protobuf::Message& GetRequestPrototype(
    const ::google::protobuf::MethodDescriptor* method) const;
  const ::google::protobuf::Message& GetResponsePrototype(
    const ::google::protobuf::MethodDescriptor* method) const;

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InstallService);
};

class InstallService_Stub : public InstallService {
 public:
  InstallService_Stub(::google::protobuf::RpcChannel* channel);
  InstallService_Stub(::google::protobuf::RpcChannel* channel,
                   ::google::protobuf::Service::ChannelOwnership ownership);
  ~InstallService_Stub();

  inline ::google::protobuf::RpcChannel* channel() { return channel_; }

  // implements InstallService ------------------------------------------

  void getWifiNetworks(::google::protobuf::RpcController* controller,
                       const ::WifiRequest* request,
                       ::WifiResponse* response,
                       ::google::protobuf::Closure* done);
 private:
  ::google::protobuf::RpcChannel* channel_;
  bool owns_channel_;
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InstallService_Stub);
};

2 个答案:

答案 0 :(得分:1)

似乎protoc没有生成阻止代码所以我不得不使用自制阻止:

bool callbackFired = false;

void myCallback() {
    // ...
    callbackFired = true;
}

// run service method
service->myMethod(rpcController, request, response, NewCallback(&myCallback));

// block the thread until callback is invoked
while (!callbackFired);

...

C ++客户端使用示例:https://github.com/4ntoine/protobuf-socket-rpc

答案 1 :(得分:-1)

执行此操作的方法是提供自己的InstallService子类,该子类将覆盖您要实现的方法:

struct MyInstallService : public InstallService
{
    void getWifiNetworks(::google::protobuf::RpcController* controller,
                       const ::WifiRequest* request,
                       ::WifiResponse* response,
                       ::google::protobuf::Closure* done) override
  {
    // do your work here

    // fill up the response here

    done->Run();  // this will trigger the response
  }
};

客户端: 像这样的东西

namespace detail {
template<class F>
struct simple_closure : google::protobuf::Closure {

    simple_closure(F f)
    : _f(std::move(f))
    {}

    void Run() override {
        _f();
    }
private:
    F _f;
};
}

template<class F>
std::unique_ptr<detail::simple_closure<F>> make_closure(F&& f) {
    return std::make_unique<detail::simple_closure<F>>(std::forward<F>(f));
}

std::unique_ptr<WifiResponse> syncGetWifiNetworks(InstallService_Stub & stub, const WifiRequest& req)
{
    auto result = std::make_unique<WifiResponse>();
    auto promise = std::promise<std::unique_ptr<WifiResponse>>;
    auto future = promise.get_future();
    auto controller = allocate_controller(); // you need to write this
    auto closure = make_closure([&result, &promise]{
        promise.set_value(std::move(result));
    });
    // assumes you already have an async comms queue - otherwise just 
    // dispatch this lambda to a std::async(std::launch::async, ...)
    comms_queue.dispatch([&controller, &req, &stub, &response]{
        stub.getWifiNetworks(controller, &req, response.get(), closure);
    };

    // HERE is where the current thread blocks until the promise is fulfilled
    return future.get();
}
相关问题