如何从 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;
}
我正在用 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;
}