如何从 protobuf 构建 rpc?
Posted
技术标签:
【中文标题】如何从 protobuf 构建 rpc?【英文标题】:how to build rpc from protobuf? 【发布时间】:2019-12-04 17:09:59 【问题描述】:我正在用 boost::asio 和 protobuf 编写“筏共识算法”。服务器通过使用两种类型的“RPC”相互通信:AppendEntryRPC 和 RequestVoteRPC。当服务器 A 从服务器 B 接收到一个已知长度的字符串时,它如何知道该字符串应该被解码为哪种 RPC 结构?
我知道这个问题有一个简单的解决方案,将接收阶段分为两个阶段:第一阶段获取 RPC 类型名称,第二阶段获取 RPC 字符串内容然后对其进行解码。但我只是想避免这样做。有什么解决办法吗?
我还知道有一个名为“grpc”的框架,但我无法在我的 Mac 上成功运行它的示例。或者有人可以用天真的语言解释“grpc”如何解决这个问题吗?
【问题讨论】:
【参考方案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 文件来反序列化。
最好的方法是构建一个具有已知结构的标头系统,这样您就知道要反序列化什么。
【讨论】:
以上是关于如何从 protobuf 构建 rpc?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 protobuf (.proto) 文件中生成 (.json/.yaml) 中的 swagger3 (OpenAPI3) 规范?
Protobuf-Net:实现服务器、rpc 控制器和 rpc 通道
如何使用 mingw 在 Windows 中构建 protobuf-c?