如何从 protobuf 构建 rpc?

how to build rpc from protobuf?

我正在用 boost::asio 和 protobuf 编写 "raft consensus algorithm"。服务器通过使用两种类型的 "RPC" 相互通信:AppendEntryRPC 和 RequestVoteRPC。当服务器A从服务器B收到一个已知长度的字符串时,它如何知道应该将字符串解码成哪种RPC结构?

我知道这个问题有一个天真的解决方案,将接收阶段分为两个阶段:第一阶段获取 RPC 类型名称,第二阶段获取 RPC 字符串内容然后对其进行解码。但我只是想避免这样做。有什么解决办法吗?

我也知道有一个名为 "grpc" 的框架,但我无法成功 运行 它在我 Mac 上的示例。或者有人可以用天真的语言解释 "grpc" 如何解决这个问题吗?

很遗憾,没有解决方案。服务器无法识别消息类型,必须事先知道。原因是每条消息/RPC 都可以有不同的 protobuff 原型文件来反序列化。

最好的方法是构建一个具有已知结构的 header 系统,这样您就知道要反序列化什么。

您可以创建一条额外的消息,它可以包含两种类型的消息并且始终可以安全解析:

message Vote {
  ...
}

message Entry {
  ...
}

message VoteOrEntry {
  oneof combined {
    Vote vote = 1;
    Entry entry = 2;
  }
}

然后使用has_vote()has_entry()来区分你的情况。

您仍将只有一封 VoteOrEntry 类型的消息。对于上面添加的新示例项目,此 write.cc 应该适用于工作:

#include <ctime>
#include <fstream>
#include <google/protobuf/util/time_util.h>
#include <iostream>
#include <string>

#include "test.pb.h"

using namespace std;

using google::protobuf::util::TimeUtil;

int main(int argc, char *argv[]) {
    GOOGLE_PROTOBUF_VERIFY_VERSION;

    if (argc != 2) {
        cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
        return -1;
    }

    cap cap;
    int type;
    cout << "Please choose a type [1, 2]: ";
    cin >> type;

    if (type == 1) {
        type1 *t1 = cap.mutable_entity1();
        string name;
        cout << "Please choose a name: ";
        cin >> name;
        int id;
        cout << "Please choose an id: ";
        cin >> id;
        t1->set_name(name);
        t1->set_id(id);

        fstream output(argv[1], ios::out | ios::trunc | ios::binary);
        if(!cap.SerializeToOstream(&output)){
            cerr<<"failed to write to file"<<endl;
            return -1;
        }
    }else{
      type2 *t2 = cap.mutable_entity2();
      int id;
      cout << "Please choose an id: ";      
      cin>>id;
      string name;
      cout << "Please choose a name: ";
      cin>>name;
      int v;
      cout << "Please choose v: ";
      cin>>v;
      t2->set_name(name);
      t2->set_id(id);
      t2->set_v(v);
      fstream output(argv[1], ios::out | ios::trunc | ios::binary);
      if(!cap.SerializeToOstream(&output)){
          cerr<<"failed to write to file"<<endl;
          return -1;
      }
    }

    google::protobuf::ShutdownProtobufLibrary();

    return 0;
}