Сериализация в C # (protobuf-Net), десериализация в C ++ (protobuf): более 5 полей в классе - PullRequest
2 голосов
/ 25 июня 2011

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

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

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).

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

1 Ответ

0 голосов
/ 25 июня 2011

Я проанализировал это в ридере в 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 ++, чтобы узнать, не один ли из нас приглянулся.

...