我正在使用google protobuf
来实现一个基于Request/Response
的简单协议。
对等方可以通过socket
Request
和Response
(当然serialized
)收到string
。
我正在使用我自己的c ++套接字实现,所以我以这种方式实现operator>>
(同样适用于operator<<
)从socket
对象接收数据:
...
template<class M>
void operator>>(M& m) throw (socks::exception) {
std::string str;
if (!this->recv(str)) {
throw socks::exception(">> failed to retrieve stream via socket");
return;
}
if (!m.ParseFromString(str))
throw socks::exception(
"failed to parse the received stream via socket");
}
因此模板参数M
可以是对象Request
和Response
。
// some lines from req_res.proto
message Request {
required action_t action = 1;
}
enum result_t {
...
}
message Response {
required result_t result = 1;
...
}
如何通过这种方式确定我是否使用Response
收到Request
或operator>>
?
my_socket_object s;
...
for (;;) {
Request|Response r;
s >> r;
...
}
...
答案 0 :(得分:2)
您可以拥有一个基本的Message
对象,并扩展协议中使用的所有其他类型:
message Message {
extensions 100 to max;
}
message Request {
extends Message {
optional Request request = 100;
}
required action_t action = 1;
}
message Response {
extends Message {
optional Response response = 101;
}
required result_t result = 1;
}
这比其他答案恕我直言中提出的鉴别器/联合解决方案更优雅,自包含且更容易扩展。
您可以进一步使用此技术进行构建,例如您的Request
/ Response
消息
message Request {
extends Message {
optional Request request = 100;
}
extensions 100 to max;
}
message Action1 {
extends Request {
optional Action1 action1 = 100;
}
optional int32 param1 = 1;
optional int32 param2 = 2;
}
message Action2 {
extends Request {
optional Action2 action2 = 101;
}
optional int32 param1 = 1;
optional int32 param2 = 2;
}
答案 1 :(得分:1)
一种可能的方法是将任何可能的消息放在另一个高级消息中作为一种标记联合:
enum protocolmessage_t {
Request = 1;
Response = 2;
}
message ProtocolMessage {
required protocolmessage_t type = 1;
optional Request request = 10;
optional Response response = 11;
}
然后,您将此ProtocolMessage
作为M
参数提供给>>
运算符,您可以检查类型并提取相应的值元素。
另一种方法是为每个消息添加1个字节的前缀,对该类型进行切换,然后使用相应的类型调用>>
运算符。