如何判断序列化协议缓冲区中的消息类型?

时间:2012-10-04 16:03:40

标签: protocol-buffers

我想在每次不使用预期的邮件类时尝试InvalidProtocolBufferException时会得到parseFrom(bytes)

我的代码如下所示:

try {

    LoginMessage msg = LoginMessage.parseFrom(bytes);
    // ... use msg ...

} catch(InvalidProtocolBufferException exception) {

    ErrorMessage error = ErrorMessage.parseFrom(bytes);
    // ... do something ...
}

我的信息是这些:

message LoginMessage
{
required Status status = 1;
optional UserMessage user= 2;
}     

message ErrorMessage
{
required Error error = 1;
}

其中TeamStatusError枚举

当我执行应该导致ErrorMessage的代码时,它会解析为LoginMessage并混淆两个枚举:error字段和status字段。

那么我怎么能区分这两种消息?

它似乎使用结构类型进行优化,因此它不传输字段名称或消息类型,但解决此问题的实际方法是什么?我不想在ErrorMessage中插入LoginMessage并始终返回LoginMessage

我考虑将error字段索引设置为其他消息不会使用的数字,例如ErrorMessage error = 15000;,但我不知道这是否正确,也不知道它是否始终有效(想象如果LoginMessage中的所有字段都是可选的,它会起作用吗?)。

1 个答案:

答案 0 :(得分:2)

不,那不会出错。枚举在序列化时只是整数,并且意外值存储在扩展数据中 - 因此字段1在消息之间完全可以互换。由于“user”是可选的,如果它不在那里也无关紧要 - 如果它 但不是预期的,它将存储在扩展数据中。

  

它似乎使用结构类型进行优化,因此它不传输字段名称或消息类型

这是正确的;传输字段编号和数据。没有名字。

分辨信息的最好方法是通过某种前缀。最简单的方法是使用包装器消息:

 message SomeWrapper {
     optional LoginMessage login = 1;
     optional ErrorMessage error = 2;
 }

然后在反序列化时,只需检查哪个字段有值。显然,在序列化时,您还需要将值包装在SomeWrapper中。请注意,未包含的可选值会产生零成本。