【问题标题】:how to build rpc from protobuf?如何从 protobuf 构建 rpc?
【发布时间】:2019-12-04 17:09:59
【问题描述】:

我正在用 boost::asio 和 protobuf 编写“筏共识算法”。服务器通过使用两种类型的“RPC”相互通信:AppendEntryRPC 和 RequestVoteRPC。当服务器 A 从服务器 B 接收到一个已知长度的字符串时,它如何知道该字符串应该被解码为哪种 RPC 结构?

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

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

【问题讨论】:

    标签: protocol-buffers


    【解决方案1】:

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

    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;
    }
    

    【讨论】:

    • 这是可能的,但有限制,RPC 大多具有不同的结构字段等。将其用于错误或状态处理是有意义的,因为它应该为各方标准化。
    • 谢谢,“oneof combied”其实是我要找的,虽然听不懂你们之间的对话。
    • @Jan-Gerd。兄弟,你能举个例子吗?因为我不能像官方的“地址簿”示例(尤其是 write)那样编写示例程序“writer and reader”。我也不能谷歌它。
    • "write(37139,0x10a25f5c0) malloc: *** 对象 0x7f8cfe500000 错误:未分配指针被释放 write(37139,0x10a25f5c0) malloc: *** 在 malloc_error_break 中设置断点进行调试"它一直抱怨 set_allocated_vote 或 set_allocated_entry
    • @YNX,请将您的代码发布到某个地方,然后我可以看看。如果这不再与 RPC 相关,请为其创建一个新问题。
    【解决方案2】:

    不幸的是,没有解决方案。服务器无法识别消息类型,必须提前知道。因为每条消息/RPC 都可以有一个不同的 protobuff proto 文件来反序列化。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-09
      • 2019-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多