Protobuf InvalidProtocolBufferException 与一些字符串

Protobuf InvalidProtocolBufferException with some strings

我们使用 protobuf v.3 通过 HTTP 将消息从 C# 客户端传输到 Java 服务器。

消息原型如下所示:

message CLIENT_MESSAGE {
    string message = 1;
}

客户端和服务器都对字符串使用 UTF-8 字符编码。

当我们使用像 "abc" 这样的短字符串值时,一切都很好,但是当我们尝试传输其中包含 198 个字符的字符串时,我们捕获了一个异常:

   com.google.protobuf.InvalidProtocolBufferException: 
    While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length.

我们尝试比较甚至包含 protobuf 数据的字节数组,但没有找到解决方案。 对于 "aaa" 字符串字节数组以此字节开头:

10 3 97 97 97

其中10为protobuf字段数,3为字符串长度,69 65 67为"aaa".

对于字符串

"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

其中包含198个字符,字节数组以此开头:

10 198 1 97 97 97....

其中10是protobuf字段号,198是字符串长度,1好像是字符串标识符什么的?

为什么 protobuf 无法解析此消息?

已经花了将近一天的时间来寻找这个问题的解决方案,感谢任何帮助。

更新:

我们从客户端和服务器都进行了转储,奇怪的是 - 转储是不同的!

在发送到服务器之前从客户端转储的 Protobuf:

00000000   0A C6 01 61 61 61 61 61  61 61 61 61 61 61 61 61   ·Æ·aaaaaaaaaaaaa
00000010   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00000020   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00000030   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00000040   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00000050   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00000060   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00000070   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00000080   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00000090   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
000000A0   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
000000B0   61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
000000C0   61 61 61 61 61 61 61 61  61                        aaaaaaaaa  

服务器接收的 Protobuf 转储:

0000: 0A EF BF BD 01 61 61 61 61 61 61 61 61 61 61 61   .....aaaaaaaaaaa
0010: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
0020: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
0030: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
0040: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
0050: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
0060: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
0070: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
0080: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
0090: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00A0: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00B0: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
00C0: 61 61 61 61 61 61 61 61 61 61 61                   aaaaaaaaaaa

如您所见,protobuf 数据 headers 是不同的...这完全打破了我的想法,怎么会这样?

UPDATE2: 我们进行了研究,发现只有长度超过 128 个符号的字符串才会出现此问题。如果字符串由 128 个或更少的符号组成 - 没有问题。

Where 10 is protobuf field number,

是;字段 1,长度前缀。

and 198 is string length, and 1 seems to be like string identifier, or what?

其中198 1为字符串长度,采用"varint"编码;这计算为整数 198,但需要两个字节进行编码。

And why protobuf cannot parse this message?

我们需要查看其余字节;如果您没有所有字节,该库可能是非常正确的。您是否有 所有 失败案例的字节,可能是十六进制或 base-64?

好吧,最后问题出在字符编码上——我们尝试将二进制 protobuf 数据转换为字符串。

如果您需要将二进制 protobuf 数据作为字符串传输 - 首先在客户端将其编码为 base64,然后在服务器上从 base64 解码。

感谢@Marc Gravell 的帮助