Исключение недопустимого типа провода на Protobuf- net десериализация с вложенными данными (от C ++ до C#) - PullRequest
3 голосов
/ 07 мая 2020

Мне дали приложение C ++ (встроенный исполняемый файл и исходный код, который сейчас не собирается), которое использует сгенерированные прото-классы для отправки сообщений protobuf. Я взял те же файлы .proto, которые он использовал для создания своих классов, и сгенерировал связанные классы в приложении C#. Цель состоит в том, чтобы иметь возможность получать и отправлять сообщения между этими приложениями, используя protobuf- net на стороне C#. Обратите внимание, что оба используют формат proto2.

Сообщения только с членами простого типа (например, int) могут быть успешно сериализованы и десериализованы. Однако, похоже, существует проблема с десериализацией сообщений с вложенными типами сообщений в мое C# приложение, например,

message Outer {
    optional Inner = 1;
}

message Inner {
    optional float f = 1;
}

Полученное сообщение типа «Внешний» не сможет десериализоваться в C# через:

Serializer.Deserialize<T>(new MemoryStream(msg)); // msg is a byte[]

, что дает «Исключение недопустимого типа провода». Я перешел по ссылке здесь , но, просмотрев эти ответы, я не нашел ничего очевидного, связанного с моей ситуацией. Я на 95% уверен, что сгенерированные классы источника и назначения совпадают, данные не повреждены, и я выполняю десериализацию до правильного типа.

Могу ли я правильно десериализовать такие вложенные типы? Есть ли проблема совместимости с тем, как были созданы классы (и как они сериализованы) в приложении C ++ по сравнению с приложением C# с использованием protobuf- net?

Здесь - это пример проекта (созданный в VS 2019 для. NET Core 3.1), который воспроизводит проблему.

1 Ответ

1 голос
/ 19 мая 2020

В моих входящих данных было около 50 дополнительных байтов «материала», которого я не ожидал (то есть не заголовка сообщения), которые не соответствовали определенному формату сообщения, поэтому данные были существенно повреждены. Трудно было сказать это, глядя на поток байтов; что выдало это, так это разница в длине сообщения, которое я сериализовал на стороне C#, по сравнению с байтами, которые я прочитал из wirehark входящего сообщения. Затем я просмотрел эти байты и нашел эквивалентные байты для моего сериализованного сообщения a небольшие пути внутрь.

Почему во входящем сообщении есть лишние "вещи" - другой вопрос, но это деталь реализации, поэтому я считаю этот вопрос закрытым.

Если это поможет кто-нибудь в подобной ситуации, я сделал небольшой тест l oop, чтобы продолжать попытки десериализовать побайтно, пока он не сработает (можно улучшить, но пока работает):

var rawBytes = msg.GetBytes(); // The raw incoming message
bool success = false;
OuterMsgType outer;
while (!success)
{
    try
    {
        rawBytes = rawBytes.Skip(1).ToArray();
        outer = ProtoBuf.Serializer.Deserialize<OuterMsgType>(new MemoryStream(rawBytes));
        if (outer?.InnerMsg != null)
             success = true;
    }
    catch (Exception e)
    {
        // Wire type exception: Ignore it, don't care
    }
}
...