web-dev-qa-db-ja.com

Google.Protobuf.InvalidProtocolBufferException:プロトコルメッセージに無効なタグ(ゼロ)が含まれていました

学校のプロジェクトに問題があります。Protobufライブラリを使用していますが、次のエラーが発生します。

Google.Protobuf.InvalidProtocolBufferException "プロトコルメッセージに無効なタグ(ゼロ)が含まれていました。

私のプロトコルメッセージラッパーは次のとおりです。

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

6
Jean Walrave

問題はおそらく、既知の長さを使用せずにGetBufferを使用したことです。 GetBuffer特大バッキング配列を返します。ストリームの_.Length_の後のデータはガベージであり、消費されるべきではありません。通常(常にではありませんが)ゼロになります。これが表示されています。

ToArray()の代わりにGetBuffer()を使用するか、ストリームの_.Length_を追跡して、特大のバッファーのその量だけを消費します。


もう1つの可能性は「フレーミング」です。パケットを処理しているように見えますが、これがTCPの場合、受信するチャンクが送信するチャンクと同じサイズであるという保証はありません。 TCPを介して複数のメッセージを送信している場合は、独自のフレーミングを実装する必要があります(バイナリデータを話しているため、通常は長さのプレフィックスを使用します)。


ちなみに、これはprotobuf-netではありません。


これらのどちらも問題ではない場合:受信したデータが正確に(バイト単位で)送信したデータ(長さを含む)であることを確認してください。 IOコードによって、データが破損したり、誤ってチャンクされたりするのは簡単です。

5
Marc Gravell