Как получить и разобрать QByteArray через UDP в структуру битовых полей? - PullRequest
0 голосов
/ 03 февраля 2020

2 структуры битовых полей объединены в одну структуру. Раньше, когда разрешался общий размер структуры, он делал объединение через объединение в uint64. Теперь размер структур стал больше, я передаю его QByteArray с сервера на клиент, и теперь возникает проблема с получением и анализом.

Как нормальные люди делают это правильно? Можно еще с примером, я буду рад!

Клиентская сторона

QDataStream stmFrom( &buffer, QIODevice::ReadWrite );

QTextStream cdl( & log );
for(int i(0); i < 5; i++)
{
    stru m;// union in it is a structure with bit fields and uint64
    stmFrom >> m.all; // from QByteArray to uint64
    cdl << m.all;// write to file
    cdl << "\n";
}

1 Ответ

0 голосов
/ 04 февраля 2020

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

Сериализация / десериализация была реализована много раз многими разработчиками / сообществами. Я думаю, что лучше использовать одну из распространенных, хорошо известных и без ошибок библиотек сериализации.

Например, https://github.com/USCiLab/cereal - достойный вариант, просто позвольте ему сериализоваться и десериализоваться для вас или просто используйте QDataStream.

Чтобы предотвратить конфликты между хостом и клиентскими компьютерами Вы можете использовать portable_archive или QDataStream.

Также, если вы используете UDP и ваши данные важны, вы должны добавить часть контрольной суммы из-за вероятности потери по UDP.

Если вы используете TCP, необходимо добавить длину сообщения в сообщение из-за его ориентированной на поток структуры.

Пример Я демонстрирую основную c, некрасивую, но реализацию более высокого уровня

#include <QDataStream>
#include <QCoreApplication>
#include <QDebug>

template< int MsgId , typename T>
struct msg
{
    int id() { return msg_id; }
    T data;

private:

    template< int Id , typename Type >
    friend QDataStream& operator<<( QDataStream& out , const msg<Id , Type>& );

    template< int Id , typename Type >
    friend QDataStream& operator>>( QDataStream& out , msg<Id , Type>& );
    int msg_id { MsgId };
};

template< int MsgId , typename T>
QDataStream& operator <<( QDataStream& out , const msg< MsgId , T >& m )
{
    return out << m.msg_id << m.data;
}

template< int MsgId, typename T>
QDataStream& operator >>( QDataStream& in , msg< MsgId , T >& m )
{
    return in >> m.msg_id >> m.data;
}

struct server_status
{
    int number_of_active_users {};
    int station_load {};
};

QDataStream& operator <<( QDataStream& out , const server_status& s )
{
    return out << s.station_load << s.number_of_active_users;
}

QDataStream& operator >>( QDataStream& in , server_status& s )
{
    return in >> s.station_load >> s.number_of_active_users;
}

struct error_occurred
{
    int code;
    QString msg;
};

QDataStream& operator <<( QDataStream& out , const error_occurred& e )
{
    return out << e.code << e.msg;
}

QDataStream& operator >>( QDataStream& in , error_occurred& e )
{
    return in >> e.code >> e.msg;
}

int main( int argc , char** argv)
{
    QCoreApplication a { argc , argv };

    // Serialize to byte array
    QByteArray msg_buffer;
    QDataStream out { &msg_buffer , QIODevice::WriteOnly };

    msg<10 , server_status> m;
    m.data.station_load = 54;
    m.data.number_of_active_users = 112;

    out << m;

    msg<11 , error_occurred> e;
    e.data.msg = "Device temperature is so high.";
    e.data.code = 401;

    out << e;

    // Send over udp
    // some_udp_socket->write( msg_buffer );

    auto incomed_datagram = msg_buffer; // some_udp_socket->receiveDatagram().data();

    QDataStream in { &incomed_datagram , QIODevice::ReadOnly };

    while( !in.atEnd() )
    {
        int msg_id {};

        in >> msg_id;

        if ( msg_id == 10  )
        {
            server_status s;
            in >> s;
            qDebug() << "station_load : %" << s.station_load << "active_users :" << s.number_of_active_users;
        }
        else if ( msg_id == 11 )
        {
            error_occurred e;
            in >> e;
            qDebug() << "code :" << e.code << "msg :" << e.msg;
        }
    }

    a.exec();
}

message_id проверяется, и соответствующий класс инициализируется вручную, но можно написать шаблонный класс, который отправляет и инициализирует сообщения в соответствии с message_id автоматически.

...