Protocol buffers Protobuf InvalidProtocolBufferException,带有一些字符串

Protocol buffers Protobuf InvalidProtocolBufferException,带有一些字符串,protocol-buffers,protobuf-csharp-port,protobuf-java,Protocol Buffers,Protobuf Csharp Port,Protobuf Java,我们使用ProtobufV.3通过HTTP将消息从C#客户端传输到Java服务器 消息proto如下所示: message CLIENT_MESSAGE { string message = 1; } 客户端和服务器都对字符串使用UTF-8字符编码 当我们使用像“abc”这样的短字符串值时,一切都很好,但当我们尝试传输包含198个字符的字符串时,我们发现了一个异常: com.google.protobuf.InvalidProtocolBufferException:

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

消息proto如下所示:

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”,字符串字节数组以以下字节开始:

1039797

其中10是protobuf字段号,3是字符串长度,69 65 67是“aaa”

对于字符串

“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

其中包含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数据头是不同的。。。这简直让我心碎,怎么会这样

更新2:我们做了一项研究,发现这个问题只发生在长度超过128个符号的字符串上。如果字符串由128个或更少的符号组成,则没有问题

其中10是protobuf字段编号

对,;字段1,长度前缀

198是字符串长度,1看起来像字符串标识符,或者什么

198 1
是字符串长度,用“varint”编码;这将作为整数198进行计算,但需要两个字节进行编码

为什么protobuf无法解析此消息


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

好吧,最后的问题是字符编码-我们尝试将二进制protobuf数据转换为字符串

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


谢谢@Marc Gravell的帮助

你好,Marc,谢谢你的回答。从客户端发送的完整字节如下所示:@NewJ此处的总缓冲区应为201字节,注意;如果你给的缓冲区不是这个长度:那就是problem@NewJ查看文件的开头;客户端发送“0A C6 01 61xlots”,服务器接收“0A EF BF BD 01 61xlots”;在服务器接收到您发送的数据之前,其他一切都无法正常工作—您在传输过程中损坏了数据。那么:为什么服务器会收到这些数据?我的猜测是您对二进制进行了文本编码,这将是非常错误的。@NewJ我扫描了我能想到的所有文本编码,没有一个能从
0A C6 01 61
生成
0A EF BF BD 01 61
,所以。。。不确定您到底做了什么,但在客户端序列化和服务器反序列化之间:数据是不同的。所以:在服务器上的数据与客户端认为它发送的数据匹配之前:所有的赌注都是无效的。我看不到那个代码,所以我真的不能推测你做了什么。@NewJ嗯,是的;这一行完全是错的——它使用的是反向文本编码。这不是将任意二进制(意思是:非编码文本)转换为字符串的有效方法。您需要的是十六进制或base-64之类的东西。我会使用base-64(它会更短),在这种情况下:
stringbase64=Convert.ToBase64String(protoBytes)。几乎每个框架都有一个预构建的API来编码或解码base-64。更新:我们做了一项研究,发现这个问题只发生在长度超过128个符号的字符串上。如果字符串由128个或更少的符号组成,则出现问题注意:如果可以避免处理字符串,那么效率会更高-base-64会增加一些开销