Как я могу написать свою собственную реализацию RP C для буферов протокола, использующих ZeroMQ - PullRequest
3 голосов
/ 06 января 2020

В соответствии с документацией Google Protocol Buffers в ' Определение сервисов ' они говорят, что

также возможно использовать буферы протокола с вашей собственной реализацией RP C.

Насколько я понимаю, Protocol Buffers не реализует RP C изначально. Вместо этого они предоставляют серию абстрактных интерфейсов, которые должны быть реализованы пользователем (это я!). Поэтому я хочу реализовать эти абстрактные интерфейсы, используя ZeroMQ для сетевого взаимодействия.

Я пытаюсь создать реализацию RP C с использованием ZeroMQ, потому что проект, над которым я работаю, уже реализует ZeroMQ для базовых c сообщений (следовательно, я не используя gRP C, как рекомендует документация).

После тщательного изучения документации к прототипу я обнаружил, что мне нужно реализовать абстрактные интерфейсы RpcChannel и RpcController для моей собственной реализации.

Я построил минимизированный пример того, где я сейчас нахожусь с моей реализацией RP C

.proto file : Пропущенная схема SearchRequest и SearchResponse для краткости

service SearchService {
    rpc Search (SearchRequest) returns (SearchResponse);
}

SearchServiceImpl.h :

class SearchServiceImpl : public SearchService {
 public:
  void Search(google::protobuf::RpcController *controller,
                    const SearchRequest *request,
                    SearchResponse *response,
                    google::protobuf::Closure *done) override {
    // Static function that processes the request and gets the result
    SearchResponse res = GetSearchResult(request);

    // Call the callback function
    if (done != NULL) {
    done->Run();
    }
    }
  }
};

MyRPCController.h :

class MyRPCController : public google::protobuf::RpcController {
 public:
    MyRPCController();

    void Reset() override;

    bool Failed() const override;

    std::string ErrorText() const override;

    void StartCancel() override;

    void SetFailed(const std::string &reason) override;

    bool IsCanceled() const override;

    void NotifyOnCancel(google::protobuf::Closure *callback) override;
 private:
  bool failed_;
  std::string message_;
};

MyRPCController. cpp - На основании this

void MyRPCController::Reset() {  failed_ = false; }

bool MyRPCController::Failed() const { return failed_; }

std::string MyRPCController::ErrorText() const { return message_; }

void MyRPCController::StartCancel() { }

void MyRPCController::SetFailed(const std::string &reason) {
  failed_ = true;
  message_ = reason;
}

bool MyRPCController::IsCanceled() const { return false; }

void MyRPCController::NotifyOnCancel(google::protobuf::Closure *callback) { }

MyRPCController::ChiRpcController() : RpcController() { Reset(); }

MyRpcChannel.h :

class MyRPCChannel: public google::protobuf::RpcChannel {
 public:
    void CallMethod(const google::protobuf::MethodDescriptor *method, google::protobuf::RpcController *controller,
                    const google::protobuf::Message *request, google::protobuf::Message *response,
                    google::protobuf::Closure *done) override;
};

Вопросы, которые у меня есть с моим примером до сих пор:

  • Где я могу вписать ZeroMQ в это?
    • Похоже, что он должен идти в RPCChannel, потому что в примерах, которые я вижу (см. 3-й кодовый блок здесь ), они передают строку, к которой привязаны порты (т.е. MyRpcChannel channel("rpc:hostname:1234/myservice");)
  • Меня интересует моя реализация RPCController, она кажется слишком простой. Должно ли больше идти сюда?
  • Как реализовать RPCChannel, похоже, он очень похож на SearchServiceImpl. Виртуальная функция 1 в этих классах имеет очень похожую сигнатуру метода, за исключением ее обобщенной c.

Вот еще несколько вопросов о переполнении стека, с которыми я сталкивался и которые содержат полезную информацию по топи c:

  1. Protobuf- Net: внедряющий сервер, контроллер rp c и канал rp c - Здесь я нашел пример для реализации RPCController.
  2. Использование буферов протокола для реализации RP C в ZeroMQ - Этот ответ интересен тем, что в верхнем ответе кажется, что он рекомендует не использовать Protobufs, встроенные в RP C форматирование для .proto файла.
    • Я также заметил то же самое понятие в этом файле, в хранилище под названием libpbrp c, которое выглядело хорошим источником для примера кода
  3. Могу ли я / должен ли я использовать существующую реализацию, такую ​​как RPCZ ?

Спасибо за вашу помощь. Надеюсь, я дал достаточно информации и понял, что я ищу. Пожалуйста, дайте мне знать, если что-то неясно или не хватает информации. Я был бы рад отредактировать вопрос соответствующим образом.

1 Ответ

3 голосов
/ 06 января 2020
  • ZeroMQ предоставляет низкоуровневый API для сетевого взаимодействия на основе сообщений, которые могут содержать любые данные.
  • ProtoBuffers - это библиотека, которая кодирует структурированные данные в виде сжатых двоичных данных и декодирует такие данные.
  • gRP C - это среда RP C, которая генерирует код для служб RP C на основе сетевых коммуникаций с функциями, которые обмениваются данными в виде данных ProtoBuffers.

И ZeroMQ, и gRP C обеспечивает поддержку сетевого взаимодействия, но по-разному. Вы должны выбрать либо ZeroMQ, либо gRP C для сетевого взаимодействия. Если вы выберете ZeroMQ, сообщения могут быть закодированы с использованием ProtoBuffers, обменивающего двоичные структурированные данные.

Основным моментом является то, что библиотека ProtoBuffers позволяет кодировать и декодировать варианты записей (аналогично объединениям C / C ++), которые могут полностью эмулировать функциональность предоставляемые службами RP C, имеющими функции обмена сообщениями ProtoBuffers.

Возможны следующие варианты:

  1. Использовать ZeroMQ с примитивами отправки и получения и закодированными вариантами сообщений ProtoBuffers, которые могут содержать различные суб сообщения типа
union Request
{
  byte msgType;
  MessageType1 msg1;
  MessageType2 msg2;
  MessageType3 msg3;
}

union Response
{
  byte msgType;
  MessageType3 msg1;
  MessageType4 msg2;
  MessageType5 msg3;
}

send(Request request);
receive(Response response);
Используйте gRP C, генерируя сервис с такими функциями, как
service MyService 
{
  rpc function1(MessageType1) returns (Response);
  rpc function2(MessageType2) returns (Response);
  rpc function3(MessageType3) returns (Response);

  rpc functionN(MessageType3) returns (MessageType5);
}

(здесь можно использовать много разных комбинаций)

Используйте только одну функцию gRP C, например
service MyService 
{
    rpc function(Request) returns (Response);
}

Параметр может зависеть от

  • предпочтительной цели для клиента: клиент на основе ZeroMQ или gRP C
  • из соображений производительности, сравнивая сервис на основе ZeroMQ с gRP C
  • , специфицирующий c, например, как используется / обрабатывается подписка в ZeroMQ против gRP Служба и клиент на основе C (см. Как правильно создать шаблон publi sh -подписки в grp c? )

Для 1-го варианта необходимо сделать много вещей по сравнению со вторым вариантом. Вы должны сопоставить тип отправленного сообщения с типами ожидаемых сообщений, которые будут получены.

Второй вариант позволит легче / быстрее понять функциональность предоставляемой услуги, если кто-то другой будет разрабатывать клиент.

Для разработки службы RP C поверх ZeroMQ I будет определять такой файл .proto с указанием функций, параметров (всех возможных входных и выходных параметров) и ошибок, таких как:

enum Function 
{
    F1 = 0;
    F2 = 1;
    F3 = 2;
}

enum Error 
{
    E1 = 0;
    E2 = 1;
    E3 = 2;
}

message Request
{ 
    required Function function = 1;
    repeated Input data = 2;
}

message Response
{ 
    required Function function = 1;
    required Error error = 2;
    repeated Output data = 3;
}

message Input
{ 
    optional Input1 data1 = 1;
    optional Input2 data2 = 2;
    ...
    optional InputN dataN = n;
}

message Output
{ 
    optional Output1 data1 = 1;
    optional Output2 data2 = 2;
    ...
    optional OutputN dataN = n;
}

message Message
{
   repeated Request requests;
   repeated Response responses;
}

и, в зависимости от идентификатора функции, во время выполнения число и типы параметров должны быть проверены.

...