Google.Protobuf.InvalidProtocolBufferException:协议消息包含无效标记(零)
Google.Protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero)
我的学校项目有问题,我使用 Protobuf 库但出现以下错误:
Google.Protobuf.InvalidProtocolBufferException" Protocol message contained an invalid tag (zero).
我的协议消息包装器是:
syntax = "proto3";
package CardGameGUI.Network.Protocol.Message;
message WrapperMessage {
enum MessageType {
HELLO_MESSAGE = 0;
JOIN_ROOM_MESSAGE = 1;
JOIN_ROOM_RESPONSE_MESSAGE = 2;
}
MessageType type = 1;
bytes payload = 2;
}
我用这个发消息:
public void SendObject<T>(Protocol.Message.WrapperMessage.Types.MessageType type, T messageObject)
{
byte[] message;
// Serialize message
using (var stream = new MemoryStream())
{
((IMessage)messageObject).WriteTo(stream);
message = stream.GetBuffer();
}
byte[] wrapper = new Protocol.Message.WrapperMessage{Type = type, Payload = Google.Protobuf.ByteString.CopyFrom(message)}.ToByteArray();
Connection.SendObject<byte[]>("ByteMessage", wrapper);
}
我的服务器处理程序:
private void IncommingMessageHandler(PacketHeader header, Connection connection, byte[] message)
{
Protocol.Message.WrapperMessage wrapper = Protocol.Message.WrapperMessage.Parser.ParseFrom(message);
switch (wrapper.Type)
{
case Protocol.Message.WrapperMessage.Types.MessageType.HelloMessage:
GetClient(connection.ConnectionInfo.NetworkIdentifier).MessageHandler(Protocol.Message.HelloMessage.Parser.ParseFrom(wrapper.Payload.ToByteArray()));
break;
}
}
包装消息完全反序列化,类型正确匹配,但在处理我的 Payload 时,出现异常。
我是不是做了坏事?
编辑:消息Payload的小屏幕
问题可能是您使用了 GetBuffer
而没有使用已知长度。 GetBuffer
returns 超大 后备阵列。流的 .Length
之后的数据是垃圾,不应被消耗 - 它通常(但不总是)为零,这就是您所看到的。
要么使用 ToArray()
而不是 GetBuffer()
,要么跟踪流的 .Length
并且只消耗那么多的超大缓冲区。
另一种可能性是 "framing" - 看起来您正在处理数据包,但如果这是 TCP,则无法保证您收到的数据块与您发送的数据块的大小相同。如果您通过 TCP 发送多条消息,您需要实现自己的框架(通常通过长度前缀,因为您正在谈论二进制数据)。
顺便说一下,这不是 protobuf-net。
如果这些都不是问题:检查您收到的数据是否与您发送的数据(包括长度)完全一致(逐字节)。数据很容易被 IO 代码损坏或错误分块。
我在这种情况下遇到了这个问题
因为我的序列化字节流丢失了 varint lenth
比如如果我序列化了一个有 672 字节的“Person.proto”消息
如果我反序列化 672 字节会遇到错误
解决策略是在672bytes中添加varint len,这样就可以得到674bytes的流
额外的数量数据是672的“varint”代码,即160,5
你可以通过函数
获取varint字节
public static byte[] VarInt(int value)
{
//data len
List<byte> varIntBuffer = new List<byte>();
int index = 0;
while (true)
{
if ((value & ~0x7f) == 0)
{
varIntBuffer.Add((byte)(value & 0x7f));
break;
}
else
{
varIntBuffer.Add((byte)((value & 0x7f) | 0x80));
value = value >> 7;
}
index++;
}
return varIntBuffer.ToArray();
}
我在尝试反序列化已初始化为固定大小的字节数组时遇到了同样的问题,但存在一个错误,这意味着我没有用原始字节填充数组(因此字节数组填充了零当我试图反序列化时)。
事实证明,在第二次读取之前,我正在从 JMS BytesMessage twice in a test case but was not calling BytesMessage.reset() 中读取字节。
我猜如果在不调用 reset()
的情况下尝试从 InputStream
中读取两次,您可能会遇到类似的错误
我的学校项目有问题,我使用 Protobuf 库但出现以下错误:
Google.Protobuf.InvalidProtocolBufferException" Protocol message contained an invalid tag (zero).
我的协议消息包装器是:
syntax = "proto3";
package CardGameGUI.Network.Protocol.Message;
message WrapperMessage {
enum MessageType {
HELLO_MESSAGE = 0;
JOIN_ROOM_MESSAGE = 1;
JOIN_ROOM_RESPONSE_MESSAGE = 2;
}
MessageType type = 1;
bytes payload = 2;
}
我用这个发消息:
public void SendObject<T>(Protocol.Message.WrapperMessage.Types.MessageType type, T messageObject)
{
byte[] message;
// Serialize message
using (var stream = new MemoryStream())
{
((IMessage)messageObject).WriteTo(stream);
message = stream.GetBuffer();
}
byte[] wrapper = new Protocol.Message.WrapperMessage{Type = type, Payload = Google.Protobuf.ByteString.CopyFrom(message)}.ToByteArray();
Connection.SendObject<byte[]>("ByteMessage", wrapper);
}
我的服务器处理程序:
private void IncommingMessageHandler(PacketHeader header, Connection connection, byte[] message)
{
Protocol.Message.WrapperMessage wrapper = Protocol.Message.WrapperMessage.Parser.ParseFrom(message);
switch (wrapper.Type)
{
case Protocol.Message.WrapperMessage.Types.MessageType.HelloMessage:
GetClient(connection.ConnectionInfo.NetworkIdentifier).MessageHandler(Protocol.Message.HelloMessage.Parser.ParseFrom(wrapper.Payload.ToByteArray()));
break;
}
}
包装消息完全反序列化,类型正确匹配,但在处理我的 Payload 时,出现异常。
我是不是做了坏事?
编辑:消息Payload的小屏幕
问题可能是您使用了 GetBuffer
而没有使用已知长度。 GetBuffer
returns 超大 后备阵列。流的 .Length
之后的数据是垃圾,不应被消耗 - 它通常(但不总是)为零,这就是您所看到的。
要么使用 ToArray()
而不是 GetBuffer()
,要么跟踪流的 .Length
并且只消耗那么多的超大缓冲区。
另一种可能性是 "framing" - 看起来您正在处理数据包,但如果这是 TCP,则无法保证您收到的数据块与您发送的数据块的大小相同。如果您通过 TCP 发送多条消息,您需要实现自己的框架(通常通过长度前缀,因为您正在谈论二进制数据)。
顺便说一下,这不是 protobuf-net。
如果这些都不是问题:检查您收到的数据是否与您发送的数据(包括长度)完全一致(逐字节)。数据很容易被 IO 代码损坏或错误分块。
我在这种情况下遇到了这个问题 因为我的序列化字节流丢失了 varint lenth
比如如果我序列化了一个有 672 字节的“Person.proto”消息 如果我反序列化 672 字节会遇到错误
解决策略是在672bytes中添加varint len,这样就可以得到674bytes的流
额外的数量数据是672的“varint”代码,即160,5
你可以通过函数
获取varint字节public static byte[] VarInt(int value)
{
//data len
List<byte> varIntBuffer = new List<byte>();
int index = 0;
while (true)
{
if ((value & ~0x7f) == 0)
{
varIntBuffer.Add((byte)(value & 0x7f));
break;
}
else
{
varIntBuffer.Add((byte)((value & 0x7f) | 0x80));
value = value >> 7;
}
index++;
}
return varIntBuffer.ToArray();
}
我在尝试反序列化已初始化为固定大小的字节数组时遇到了同样的问题,但存在一个错误,这意味着我没有用原始字节填充数组(因此字节数组填充了零当我试图反序列化时)。
事实证明,在第二次读取之前,我正在从 JMS BytesMessage twice in a test case but was not calling BytesMessage.reset() 中读取字节。
我猜如果在不调用 reset()
InputStream
中读取两次,您可能会遇到类似的错误