Russian Qt Forum

Qt => Работа с сетью => Тема начата: darkfog от Июнь 07, 2018, 14:07



Название: Десериализация данных в TCP
Отправлено: darkfog от Июнь 07, 2018, 14:07
Создал простые клиент сервер. И вот вопрос при сериализации и отправке нескольких классов(или в простом случае несколько переменных разных типов), как определить на стороне клиента какой класс пришел для правильной десериализации? Можно при отправке в потоке QDataStream после начальных значений размера пакета добавить числовой идентификатор типа(класса). И на стороне сервера делать проверку if чтобы использовать нужную десериализацию. Но если классов для передачи бедет например 100 это не выглядит хорошо. Есть ли красивый способ решить эту задачу?


Название: Re: Десериализация данных в TCP
Отправлено: deMax от Июнь 07, 2018, 15:06
Передавайте строку с именем класса.


Название: Re: Десериализация данных в TCP
Отправлено: darkfog от Июнь 07, 2018, 15:29
Передавайте строку с именем класса.

Класса как такового сейчас нет(не знаю какой будет). Представь что первый раз передается строка QString, а второй картинка QImage. QDataStream может их сам сериализовать, но вот определить что пришла именно картинка не может. Нужно самому создать переменную  QImage im и в нее поместить значение из потока.    

QTcpSocket* pClientSocket = (QTcpSocket*)sender();
QDataStream in(pClientSocket);
QImage im;
in >> im;

Что бы понять что пришло изображение я на второе место после размера отправленного пакета помещаю идентификатор типа(например 1)

QTcpSocket* m_pTcpSocket;//объявлен в .h

QByteArray  arrBlock;
QDataStream out(&arrBlock, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_3);
QByteArray pic;
int type;
QFile file("D:/image");
file.open(QIODevice::ReadOnly);
pic = file.readAll(); //bit-picture
type = 1;
out << quint16(0) << type << pic;
m_pTcpSocket->write(arrBlock);

И на стороне сервера при получении делаю проверку полученного идентификатора типа.

QTcpSocket* pClientSocket = (QTcpSocket*)sender();
    QDataStream in(pClientSocket);
    in.setVersion(QDataStream::Qt_5_3);
    for (;;)
    {
        if (!m_nNextBlockSize)
        {
            if (pClientSocket->bytesAvailable() < (int)sizeof(quint16))//проверяем размер
            {
                break;
            }
            in >> m_nNextBlockSize;
        }

        if (pClientSocket->bytesAvailable() < m_nNextBlockSize)
        {
            break;
        }
        QByteArray image;
        QImage im;
        int type;
        in >> type;
        if(type == 1)//проверяем тип
        {
            in >> image;
            im = QImage::fromData(image, "TGA");
            m_ptxt->setPixmap(QPixmap::fromImage(im));
            m_ptxt->show();
            m_nNextBlockSize = 0;
        }

И вот представте что передано дофига разных типов переменных, и каждый раз проверка на if не выглядит хорошим решением. Можно использовать switch он побыстрее но я хочу узнать есть ли другой способ узнать какой тип(класс) пришел от клиента.
Проблема не в десериализации, а в определении пришедшего типа(повышение быстродействия). Может есть хороший метод для этого. Подобное должно использоваться в многопользовательских играх по идее.


Название: Re: Десериализация данных в TCP
Отправлено: sergek от Июнь 07, 2018, 16:37
Без реализации какого-то протокола вам не обойтись. Передаваемые данные в любом случае должны предваряться заголовком фиксированной длины, где, как минимум, должна содержаться информация о размере передаваемых данных и о типе.


Название: Re: Десериализация данных в TCP
Отправлено: deMax от Июнь 07, 2018, 17:08
Ну пришли к вам данные, дальше что хотите? вызвать одну из 100 функций передав ей обьект? тогда - QMap<QString, std::function> callBackMap
Можно с библиотеками заморочиться вызывая функции по имени.
Или готовые протоколы заюзать: json, protobuf...

выбор за Вами...


Название: Re: Десериализация данных в TCP
Отправлено: darkfog от Июнь 19, 2018, 15:29
Короче решил делать через switch с передачей идентификатора класса и не парится пока.