Protobuf 反序列化异常
Posted
技术标签:
【中文标题】Protobuf 反序列化异常【英文标题】:Protobuf deserialize exception 【发布时间】:2018-08-27 15:51:09 【问题描述】:尝试在 Java 中使用 protobuf 反序列化消息并获得以下异常。
原因:com.google.protobuf.InvalidProtocolBufferException:解析协议消息时,输入在字段中间意外结束。这可能意味着输入已被截断,或者嵌入的消息误报了自己的长度。 在 com.google.protobuf.InvalidProtocolBufferException.truncatedMessage(InvalidProtocolBufferException.java:86) 在 com.google.protobuf.CodedInputStream$ArrayDecoder.readRawLittleEndian64(CodedInputStream.java:1179) 在 com.google.protobuf.CodedInputStream$ArrayDecoder.readFixed64(CodedInputStream.java:791) 在 com.google.protobuf.UnknownFieldSet$Builder.mergeFieldFrom(UnknownFieldSet.java:534) 在 com.google.protobuf.GeneratedMessageV3.parseUnknownFieldProto3(GeneratedMessageV3.java:305)
【问题讨论】:
嗯……对吗?您可以使用 protogen.marcgravell.com/decode 之类的工具来检查 protobuf 有效负载。当人们使用过大的数组作为缓冲区并忘记从末尾修剪未写入的零时,我经常看到这种情况。 这是消息的字节串。 \n\x14id:article:v1:964000\x12$\n\x10predicted_topics\x12\x06IS/biz\x1a\x08\xf0l\x8f\xdep\x9f\xe4? 你有十六进制或base-64的吗?如果您可以发布 hex 或 base-64,我会更高兴我们谈论相同的字节 我不太确定。我使用 Python 的 SerializeToString 来序列化一个类。我完全不知道 API 的作用。 【参考方案1】:我已经手动解码了你的字符串,我同意这个库:你的消息被截断了。我猜测这是因为您使用的是基于字符串的 API,并且数据中有一个零字节 - 许多文本 API 看到一个零字节(NUL
ASCII 术语) 表示字符串的结尾。
以下是细分:
\n=10=field 1, length prefix - I'm assuming this is a string
\x14=20
"id:article:v1:964000"
(22 bytes used for field 1)
\x12=18=field 2, length prefix - I'm assuming this is a sub-messssage
$=36
\n=10=field 1, length prefix - I'm assuming this is a string
\x10=16
"predicted_topics"
(18 bytes used for field 2.1)
\x12=18=field 2, length prefix - I'm assuming this is a string
\x06=6
"IS/biz"
(8 bytes used for field 2.2)
\x1a=26=field 3, length prefix - I'm assuming this is "bytes"
\x08=8
\xf0
l
\x8f
\xde
p
\x9f
\xe4
(unexpected EOF)
最后,我们尝试解码最内层消息的 8 个字节,而我们只剩下 7 个字节。我知道这不是子消息,因为这会导致标签无效,而且它看起来不像 UTF-8,所以我假设这是一个 bytes
字段(但坦率地说它不是问题:我们需要 8 个字节,而我们只有 7 个)。
我的猜测是bytes
字段中的最后一个字节为零;如果我们假设最后缺少\x00
,那么字段 2.3 是 10 个字节,我们已经占了 18+8+10=36 个字节,这将使子消息(字段 2)完整。 在外部子消息之后可能还有更多丢失的数据 - 我无法知道。
所以:请确保您没有将基于文本的 API 用于二进制数据。
【讨论】:
感谢您指出这一点。我将从这里开始调试。以上是关于Protobuf 反序列化异常的主要内容,如果未能解决你的问题,请参考以下文章
protobuf-net:反序列化 Guid 属性的错误线型异常
Protobuf-net 使用嵌套数据反序列化时出现无效的线型异常(C++ 到 C#)