Сериализация в C# (protobuf-net), десериализация в C++ (protobuf): более 5 полей в классе

У меня возникли проблемы с десериализацией объекта на C++, который я сериализовал на C#, а затем отправил по сети с помощью ZMQ. Я совершенно уверен, что часть ZMQ работает правильно, потому что серверное приложение C++ (Linux) успешно получает сериализованные сообщения от C# (Windows) и отправляет их обратно в Windows, где оно может успешно десериализовать сообщение, поэтому я не думаю, что я Я испытываю какие-либо усеченные или отброшенные пакеты в этом отношении.

Однако, когда я получаю сообщение на сервере Linux, метод десериализации C++ неправильно десериализует, он выбрасывает какую-то кучу двоичных данных в 6-е поле (я вижу это в MyObject.DebugString()), но нет данных в любые другие поля. Однако странная часть здесь заключается в том, что класс, который у меня был с 5 полями, работает отлично. С++ правильно десериализует его, и все данные работают правильно. Ниже приведены несколько лакомых кусочков моего кода. Любая помощь будет принята с благодарностью.

C#:
    MemoryStream stream = new MemoryStream();
    ProtoBuf.Serializer.Serialize<TestType>(stream, (TestType)data);
    _publisher.Send(stream.ToArray());

C++:
    message_t data;
    int64_t recv_more;
    size_t recv_more_sz = sizeof(recv_more);
    TestType t;
    bool isProcessing = true;
    while(isProcessing)
    {
      pSubscriber->recv(&data, 0);
      t.ParseFromArray((void*)(data.data()),sizeof(t));
      cout<<"Debug: "<<t.DebugString()<<endl;  

      pSubscriber->getsockopt(ZMQ_RCVMORE, &recv_more, &recv_more_sz);
      isProcessing = recv_more;
    }

Вывод выглядит следующим образом:

Debug: f: "4\000\000\000\000\000\"

У меня проблемы с копированием и вставкой, но вывод продолжается, вероятно, на 3 или 4 строки.

Это мой класс TestType (протофайл):

package Base_Types;

enum Enumr {
  Dog = 0;
  Cat = 1;
  Fish = 2;
}

message TestType {
  required double a = 1;
  required Enumr b = 2;
  required string c = 3;
  required string d = 4;
  required double e = 5;
  required bytes f = 6;
  required string g = 7;
  required string h = 8;
  required string i = 9;
  required string j = 10;
}

Поле «f» указано как байты, потому что, когда это была строка, прежде чем она давала мне предупреждение о кодировке UTF-8, однако, когда этот класс работал только с 5 полями (перечисление было одним из них), он не давал мне эту ошибку. Это похоже на то, что вместо десериализации он бросает двоичный файл для всего класса в поле «f» (поле 6).

Решение. Возникла проблема, из-за которой память не копировалась перед отправкой в ​​сокет потока. Когда издатель отправил обратно, он упаковал данные и изменил то, что получил маршрутизатор. На стороне C++ должен быть memcpy(), чтобы отправлять данные для внутреннего использования. Спасибо за помощь.


person Calvin de Vries    schedule 24.06.2011    source источник
comment
Марк Гравелл... Где ты?   -  person Chandu    schedule 25.06.2011
comment
Интересно. Пара вопросов - в С# успешно ли работает DeepClone()? И какая версия protobuf-net (чтобы я мог разобраться)?   -  person Marc Gravell    schedule 25.06.2011
comment
@Cybernate Вот здесь, спасибо   -  person Marc Gravell    schedule 25.06.2011
comment
Я не пробовал DeepClone(), попробую через минуту. Версия protobuf-net.dll — CF35 от protobuf-net r282.   -  person Calvin de Vries    schedule 25.06.2011
comment
на самом деле, DeepClone() успешно   -  person Calvin de Vries    schedule 25.06.2011
comment
@ Кальвин хорошо, это говорит о том, что это не совсем безумие! Я предполагаю, что g, h, i, j имеют правильные значения? Есть ли шанс, что вы можете показать шестнадцатеричный (или base64, если проще) двоичный файл? Я хотел бы проверить, что написано... Просто чтобы быть уверенным...   -  person Marc Gravell    schedule 25.06.2011
comment
(Я автор protobuf-net, кстати, так что я весь в ушах)   -  person Marc Gravell    schedule 25.06.2011
comment
@Марк, я думаю, это то, что ты ищешь: 09-00-00-00-00-00-00-14-40-10-00-1A-00-22-02-79-6F-29-00 -00-00-00-00-00-18-40-32-02-68-69-3А-03-68-6Ф-77-42-03-61-72-65-4А-03-79-6Ф -75-52-03-73-69-72   -  person Calvin de Vries    schedule 25.06.2011
comment
О, и да, g, h, i, j все имели правильные значения. И большое спасибо за внимание к этому, я очень ценю это!   -  person Calvin de Vries    schedule 25.06.2011
comment
Я просто хочу проверить - как вы упаковываете эти данные для передачи по сети? Вы даете это как двоичный файл? Или как струна? (причина, по которой я спрашиваю: сегодня вечером у меня также был отчет об ошибке, который оказался кодом конечного пользователя, использующим неправильные механизмы для упаковки двоичного кода в виде строки)   -  person Marc Gravell    schedule 25.06.2011
comment
_publisher.Send(stream.ToArray()); отправляет его по сети в виде byte[]   -  person Calvin de Vries    schedule 25.06.2011
comment
чтобы быть более конкретным, _publisher — это сокет zmq, который принимает byte[] и отправляет его как двоичный файл.   -  person Calvin de Vries    schedule 25.06.2011


Ответы (1)


Я проанализировал его через ридер в v2, и кажется, что он имеет смысл:

1=5
2=0
3=
4=yo
5=6
6=2 bytes, 68-69
7=how
8=are
9=you
10=sir

Обратите внимание, что я сделал это исключительно из шестнадцатеричных данных (не используя .proto), но они должны быть близки к исходным данным. Но самое главное, он кажется целым.

Итак: первое, что нужно сделать; убедитесь, что двоичный файл, который вы получаете на стороне C++, точно такой же, как и двоичный файл, который вы отправили; это вдвойне важно, если вы выполняете какие-либо переводы по пути (например, двоичный => строка - что должно быть выполнено с помощью base-64).

вторая вещь; если это не сработает, возможно проблема в реализации C++. Кажется маловероятным, поскольку это одно из любимцев Google, но нет ничего невозможного. Если двоичный файл окажется неповрежденным, но все равно будет вести себя странно, я могу попробовать поговорить с людьми из C++, чтобы узнать, не сошел ли кто-нибудь из нас с кукушкой.

person Marc Gravell    schedule 24.06.2011