12

I have a problem with my school project, i use Protobuf library but i have the following error:

Google.Protobuf.InvalidProtocolBufferException" Protocol message contained an invalid tag (zero).

My protocol message wrapper is:

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;
}

I use this to send a message:

    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);
    }

And my server handler:

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;
        }
    }

The wrapper message is perfectly unserialized, and type is correctly matched, but at the treatment of my Payload, the exception pops.

Do i do something bad?

Edit: a small screen of the message Payload Payload

Jean Walrave
  • 191
  • 1
  • 2
  • 13

3 Answers3

7

The problem is probably that you used GetBuffer without making use of the known length. GetBuffer returns the oversized backing array. The data after the stream's .Length is garbage and should not be consumed - it will typically (but not always) be zeros, which is what you are seeing.

Either use ToArray() instead of GetBuffer(), or track the .Length of the stream and only consume that much of the oversized buffer.


Another possibility is "framing" - it looks like you're handling packets, but if this is TCP there is no guarantee that the chunks you receive are the same sizes as the chunks you send. If you are sending multiple messages over TCP you need to implement your own framing (typically via a length prefix, since you're talking binary data).


Incidentally, this isn't protobuf-net.


If neither of those is the problem: check the data you receive is exactly (byte for byte) the data you send (including lengths). It is easy for data to get corrupted or mis-chunked by IO code.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
0

i encounter this problem in this case because my serialize bytestream loss the varint lenth

such as if i serialize a "Person.proto" message which have 672 bytes if i deserialize the 672 bytes will encounter the error

the solve strategy is that add the varint len in the 672bytes so youcan get a 674bytes stream

the extra amount data is the "varint" code for 672, which is 160,5

you can get the varint bytes by the function

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();
}
0

I had this same issue when attempting to deserialize a byte array which had been initialized to a fixed size but there was a bug which meant I was not populating the array with proto bytes (so the byte array was populated with zeros when I was attempting to deserialize).

It turns out that I was reading bytes from a JMS BytesMessage twice in a test case but was not calling BytesMessage.reset() before the second read.

I'm guessing you could get a similar bug if attempting to read from an InputStream twice without calling reset()

lance-java
  • 25,497
  • 4
  • 59
  • 101