Как мне прочитать объект класса из QTcpSocket, используя QDataStream?

У меня есть класс, определенный мной, скажем, MyClass. Я хотел бы отправить объект этого класса через QTcpSocket. В этом ответе предлагается использовать QDataStream и это показывает, как можно перегрузить операторы << и >> для достижения этой цели.

Пока мне удалось перегрузить операторы << и >> для QDataStream. Что касается отправки и получения, я следую указаниям из этого ответа от Marek R, который отвечает на вопрос, более или менее дублирующий этот. Мой серверный код, который отправляет объект MyClass, похоже, работает. Однако я не могу понять, как получить и отформатировать данные из файла QDataStream.

Из Marek R ответа ,

void SomeClass::slotReadClient() { // slot connected to readyRead signal of QTcpSocket
    QTcpSocket *tcpSocket = (QTcpSocket*)sender();
    QDataStream clientReadStream(tcpSocket);

    while(true) {
        if (!next_block_size) {
            if (tcpSocket->bytesAvailable() < sizeof(quint16)) { // are size data available
                break;
            }
            clientReadStream >> next_block_size;
        }

        if (tcpSocket->bytesAvailable() < next_block_size) {
            break;
        }
        QString str;
        clientReadStream >> str;

        next_block_size = 0;
    }
}

Однако, когда я использую это, я получаю сообщение об ошибке:

error: no matching function for call to ‘QDataStream::QDataStream(QTcpSocket*&, QIODevice::OpenModeFlag)’

Исходя из способа отправки, пробовал следующим образом:

    MyClass obj;
    QByteArray block;
    QDataStream rs(&block,QIODevice::ReadWrite);
    rs.setVersion(QDataStream::Qt_5_7);
    int nextblocksize = 0;
    while(true)
    {
        if(!nextblocksize)
        {
            if(socket->bytesAvailable() < sizeof(quint16))
            {
                break;
            }
            socket->read(block,socket->bytesAvailable());
            rs>>nextblocksize;
        }
        if(socket->bytesAvailable() < nextblocksize)
        {
           break;
        }
        socket->read(block,socket->bytesAvailable());
        rs>>obj;
        nextblocksize=0;
    }

Однако это дает следующую ошибку:

error: conversion from ‘QByteArray’ to ‘char*’ is ambiguous
             socket->read(block,socket->bytesAvailable());
                                                        ^

Для справки, ниже приведен код для отправки, который успешно компилируется (не могу проверить, пока не заработает код для чтения):

QTcpSocket *socket = server->nextPendingConnection();
QByteArray block;
MyClass obj(1,2.0, "Hi\n");
QDataStream ds(&block,QIODevice::ReadWrite);
ds.setVersion(QDataStream::Qt_5_7);
ds<<quint16(0)<<obj;
socket->write(block);

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

Как мне это сделать?

Кроме того, каково значение quint16(0), отправленного в начале блока? Утверждается, что он служит индикатором размера блока, но как он это делает? Разве это не то же самое, независимо от размера блока? Или я совершенно неправильно понял его использование?

Спасибо.


person GoodDeeds    schedule 27.02.2017    source источник
comment
Почему бы просто не написать функции serializeToJson и deserializeFromJson? Было бы проще.   -  person Mher Didaryan    schedule 27.02.2017
comment
@MherDidaryan Я думал, что таким образом можно отправлять только строки. Не могли бы вы привести пример или указать мне источник?   -  person GoodDeeds    schedule 27.02.2017
comment
Да, вы отправляете байты (QByteArray). QJsonDocument имеет метод toJson, который возвращает QByteArray.   -  person Mher Didaryan    schedule 27.02.2017


Ответы (1)


Если MyClass реализует QJsonObject serializeToJson() and void deserializeFromJson(const QJsonObject&), вы можете отправить JSON-представление вашего класса. Думаю, так было бы проще.

class Serializable
{
public:
Serializable(){}
virtual ~Serializable(){}

virtual QJsonObject serialize_to_json() = 0;
};

class Deserializable
{
public:
Deserializable(){}
virtual ~Deserializable(){}
virtual void deserialize_from_json(const QJsonObject&) = 0;
};

// MyClass implements Serializable and Deserializable
MyClass obj;

// To wrire
// construct QJsonDocument from serializeToJson
// write bytes representing the json 
// QJsonDocument::toJson() returns QByteArray
socket->write(QJsonDocument(obj.serializeToJson()).toJson());


// To read
// Construct QJsonDocument from received bytes
// QJsonDocument::fromJson(bytes).toObject returns QJsonObject
MyClass obj;
obj.deserializeFromJson(QJsonDocument::fromJson(socket->readAll()).toObject());

Я опускаю часть проверки json. разбор json

person Mher Didaryan    schedule 27.02.2017
comment
Спасибо. Как мне реализовать serializeToJson() и deserializeFromJson()? Более того, что, если в моем классе есть типы указателей? Может ли этот метод справиться с этим? - person GoodDeeds; 27.02.2017
comment
QJsonObject имеет функцию вставки. jsonObj.insert(name, this-›getName()); Ваши типы указателей также могут реализовывать интерфейс Serializable. - person Mher Didaryan; 27.02.2017