Russian Qt Forum

Qt => Работа с сетью => Тема начата: deMax от Март 31, 2015, 08:42



Название: [РЕШЕНО] Сериализация данных для передачи по сети
Отправлено: deMax от Март 31, 2015, 08:42
Клиент на Qt, сервер С++ (bost).

Есть структуры описывающие предметную область, как лучше их передавать по сети?
Структуры без указателей, типы: вектора(в том числе и на структуры), строки, простые типы.


Название: Re: Сериализация данных для передачи по сети
Отправлено: Пантер от Март 31, 2015, 08:43
Да как хочешь, хоть в xml перегоняй. :)


Название: Re: Сериализация данных для передачи по сети
Отправлено: gil9red от Март 31, 2015, 08:54
Json тоже неплох :)


Название: Re: Сериализация данных для передачи по сети
Отправлено: Igors от Март 31, 2015, 08:58
Если простые структуры, то проще использовать операторы << и >>. И создать теги, по-взрослому


Название: Re: Сериализация данных для передачи по сети
Отправлено: deMax от Март 31, 2015, 09:05
Json тоже неплох :)
Объем передаваемых данных приличный, чтобы текстовый формат и парсинг использовать.

Да как хочешь, хоть в xml перегоняй. :)
Для каждой структуры придется писать функцию сериализации и десериализации, можно ли это сделать автоматически?

Например как автоматически запаковать/распаковать это:
Код:
struct Data {
  std::string text;
  std::vector<Data> tree;}


Название: Re: Сериализация данных для передачи по сети
Отправлено: Old от Март 31, 2015, 09:42
msgpack
google protobuf


Название: Re: Сериализация данных для передачи по сети
Отправлено: sergek от Март 31, 2015, 10:45
Может, попробовать преобразовать класс в QVariant, а потом через QDataStream - в QByteArray, который передавать проще простого. Примерно так:
Код:
class MyClass{
public:
    int i;
    double d;
    QString str;
    MyClass();
};

Q_DECLARE_METATYPE(MyClass);

    MyClass s;
    QVariant var;
    var.setValue(s); // copy s into the variant

    QByteArray arr;
    QDataStream out(&arr,QIODevice::WriteOnly);
    out << *((QVariant*)var);   
   
    int dataLen = arr.size();
    char* data = arr.data();

    // передаем dataLen байт
    ...

    // принимаем и делаем обратное преобразование
    QByteArray arr = QByteArray::fromRawData(ptr,dataLen);
    QDataStream in(&arr,QIODevice::ReadOnly);
    QVariant val(in);

    // retrieve the value
    MyClass s2 = val.value<MyClass>();

Но как в структуре использовать стандартные вектора - без понятия.


Название: Re: Сериализация данных для передачи по сети
Отправлено: Igors от Март 31, 2015, 11:12
Для каждой структуры придется писать функцию сериализации и десериализации, можно ли это сделать автоматически?
Избегать этого не следует. И лучше не ф-цию а операторы << и >>, они уже сделаны для Qt типов

Например как автоматически запаковать/распаковать это:
Код:
struct Data {
  std::string text;
  std::vector<Data> tree;}
Напр так
Код
C++ (Qt)
template <class stream>
stream & operator << ( stream & strm, const Data & data )
{
strm << data.text << data.tree;
}
 
template <class stream>
stream & operator >> ( stream & strm, Data & data )
{
strm >> data.text >> data.tree;
}
Да, придется писать операторы для std::string и std::vector, напр
Код
C++ (Qt)
template <class stream, class vec>
stream & operator << ( stream & strm, const vec & data )
{
strm << data.size();
for (size_t i = 0; i < data.size(); ++i)
 strm << data[i];
}
Но это надежно, капитально. А пытаясь словчить, сэкономить Вы потом потеряете куда больше времени латая дыры


Название: Re: Сериализация данных для передачи по сети
Отправлено: deMax от Март 31, 2015, 12:48
Old, Igors спасибо.

protobuf неплохая штука, не знал. Возможно позже добавлю.

Через потоки в принципе неплохое решение получается. Я примеры похожие видел, только с вектором не додумался.

p.s. в идеале хотелось бы макрос который сам сгенерирует эти функции.


Название: Re: [РЕШЕНО] Сериализация данных для передачи по сети
Отправлено: deMax от Апрель 01, 2015, 09:07
strm >> data.text >> data.tree;
Если использовать std::stringstream (вместо QDataStream) то все данные уходят в строку, есть ли аналоги потоков на с++ или строку по символу считывать?


Название: Re: [РЕШЕНО] Сериализация данных для передачи по сети
Отправлено: Old от Апрель 01, 2015, 09:38
strm >> data.text >> data.tree;
Если использовать std::stringstream (вместо QDataStream) то все данные уходят в строку, есть ли аналоги потоков на с++ или строку по символу считывать?
А вам msgpack не понравился?


Название: Re: [РЕШЕНО] Сериализация данных для передачи по сети
Отправлено: deMax от Апрель 01, 2015, 09:52
На хабре (http://habrahabr.ru/post/251177/) статью смотрел. Смутило следующее:
Цитировать
И скормил его всем упаковщикам. Пикл в этом списке лишь из-за того что сервер на пайтоне.

На выходе я получил такие цифры упаковки
Size test
19266 cbor
19284 msgpack
41726 json
25363 pickle

Ну, круто. Действительно качественная упаковка, жаль только под CBOR в пайтон версии нету stringref, былоб еще мельче.
А что со скоростью упаковки и распаковки?

Этот самый объект скушал 100 раз в цикле каждому упаковщику.
4.65940260887146 cbor
4.218739032745361 msgpack
0.2644484043121338 json
0.057727813720703125 pickle

4.5 секунды, как-то много всего для 100 разовой упаковки.
msgpack идет вместе с С++ кодом, а не упаковывается чисто на пайтоне, но все равно 4.2 секунды — слишком много
json показал нормальный результат, а вот пикл невероятно порадовал.

Упаковка пол беды, что с распаковкой?

4.128425598144531 cbor
7.117578029632568 msgpack
0.19976019859313965 json
0.08250904083251953 pickle

Хммм, CBOR показал такие-же как и при упаковке, а вот message pack подкачала.
JSON в пределах нормы, пикл снова радует.

У меня приложение клиент сервер, все данные на сервере, их не мало и они постоянно обновляются(сервер с удаленными БД работает).

Но для развития посмотрю.


Название: Re: [РЕШЕНО] Сериализация данных для передачи по сети
Отправлено: Old от Апрель 01, 2015, 09:54
Попробуйте сами протестировать, а не принимать решения по статьям с хабра. :)


Название: Re: [РЕШЕНО] Сериализация данных для передачи по сети
Отправлено: Igors от Апрель 01, 2015, 10:32
Если использовать std::stringstream (вместо QDataStream) то все данные уходят в строку, есть ли аналоги потоков на с++ или строку по символу считывать?
Если Вы планируете сохранять данные в читабельном виде (stringstream, QTextStream), то Вы и отвечаете за их формат (разделители, концы строк и.т.п). Делайте свой поток на базе stringstream, где напр строки будут браться в кавычки. Непонятно зачем нужен текст для передачи по сети.


Название: Re: [РЕШЕНО] Сериализация данных для передачи по сети
Отправлено: gil9red от Апрель 01, 2015, 10:42
На хабре (http://habrahabr.ru/post/251177/) статью смотрел. Смутило следующее:
Цитировать
И скормил его всем упаковщикам. Пикл в этом списке лишь из-за того что сервер на пайтоне.

На выходе я получил такие цифры упаковки
Size test
19266 cbor
19284 msgpack
41726 json
25363 pickle

Ну, круто. Действительно качественная упаковка, жаль только под CBOR в пайтон версии нету stringref, былоб еще мельче.
А что со скоростью упаковки и распаковки?

Этот самый объект скушал 100 раз в цикле каждому упаковщику.
4.65940260887146 cbor
4.218739032745361 msgpack
0.2644484043121338 json
0.057727813720703125 pickle

4.5 секунды, как-то много всего для 100 разовой упаковки.
msgpack идет вместе с С++ кодом, а не упаковывается чисто на пайтоне, но все равно 4.2 секунды — слишком много
json показал нормальный результат, а вот пикл невероятно порадовал.

Упаковка пол беды, что с распаковкой?

4.128425598144531 cbor
7.117578029632568 msgpack
0.19976019859313965 json
0.08250904083251953 pickle

Хммм, CBOR показал такие-же как и при упаковке, а вот message pack подкачала.
JSON в пределах нормы, пикл снова радует.

У меня приложение клиент сервер, все данные на сервере, их не мало и они постоянно обновляются(сервер с удаленными БД работает).

Но для развития посмотрю.

Там также говорилось, что связка json+zip очень хорошая :)


Название: Re: [РЕШЕНО] Сериализация данных для передачи по сети
Отправлено: deMax от Апрель 01, 2015, 11:03
Непонятно зачем нужен текст для передачи по сети.
В какой контейнер засовывать данные? std::vector<char> ?

Сервер будет написан на boost::asio без Qt.
std такой неудобный после Qt. В Qt взял классик и все работает, у тут пили напильником эти поделки.


Название: Re: [РЕШЕНО] Сериализация данных для передачи по сети
Отправлено: Igors от Апрель 01, 2015, 13:38
Непонятно зачем нужен текст для передачи по сети.
В какой контейнер засовывать данные? std::vector<char> ?
Зачем куда-то засовывать? Просто пишите-читайте, пример
Код
C++ (Qt)
class MyOutStream : public std::ofstream {
public:
template <class T>
MyOutStream & WriteSimple( T val )
{
  write((char *) &val, sizeof(val));
  return *this;
}
 
MyOutStream & operator << ( size_t val ) { return WriteSimple(val); }
MyOutStream & operator << ( int val )      { return WriteSimple(val); }
MyOutStream & operator << ( float val )   { return WriteSimple(val); }
 
MyOutStream & operator << ( const std::string & str )
{
  (*this) << str.size();
  write(str.c_str(), str.size());
  return *this;
}
 
MyOutStream & operator << ( const char * str )
{
  (*this) << strlen(str);
  write(str, strlen(str));
  return *this;
}
 
template <class T>
MyOutStream & operator << ( const std::vector<T> & vec )
{
  (*this) << vec.size();
  for (size_t  i = 0; i < vec.size(); ++i)
   (*this) << vec[i];
 
  return *this;
}
};