Russian Qt Forum

Qt => Общие вопросы => Тема начата: studert от Декабрь 08, 2008, 13:49



Название: Вопрос по работе с QDataStream?
Отправлено: studert от Декабрь 08, 2008, 13:49
Получаю данные с сокета в QbyteArray, далее необходимо эти данные "разложить по полочкам", то есть по разным переменным:

QByteArray datagramOut,datagramIn;
QDataStream datagramOutStream(&datagramOut, QIODevice::WriteOnly);
QDataStream datagramInStream(&datagramIn, QIODevice::ReadOnly);
читаю данные:
udpSocket.readDatagram(datagramIn.data(),datagramIn.size());
раскладываю по полочкам:
datagramInStream>>temp>>ReceivedFrameType>>ReceivedCommand>>ReceivedOperationMode
    >>ReceivedPacketNumber>>ReceivedWindowWidth>>ReceivedWindowHeight>>ReceivedFirstRow
    >>ReceivedLastRow;
потом читаю новые данные в datagramIn, далее необходимо снова разложить по полочкам данные, но как я понял qdataInStream указывает на ту позицию в которой закончили читать предыдущие данные. Можно ли сбросить поток к началу новых данных? Или придется "ручками" побайтно разбирать QbyteArray и "раскладывать по полочкам".


Название: Re: Вопрос по работе с QDataStream?
Отправлено: Rcus от Декабрь 08, 2008, 14:05
Код
C++ (Qt)
bool QIODevice::reset ()   [virtual]
bool QIODevice::seek ( qint64 pos )   [virtual]

А еще можно каждый раз создавать QDataStream заново :)


Название: Re: Вопрос по работе с QDataStream?
Отправлено: studert от Декабрь 09, 2008, 09:29
Не пинайте сильно за тупые вопросы, но что-то я не понимаю как использовать функцию reset() или seek(), она же применима к объекту QIODevice, а я использую QDataStream и QbyteArray.
По поводу второго совета, мне тоже приходила идея создавать каждый раз заново QDataStream, но я собираюсь многократно (483 раза) его использовать. Как заменять объект новым не меняя имени? Нужно сначала убить старый?


Название: Re: Вопрос по работе с QDataStream?
Отправлено: BRE от Декабрь 09, 2008, 09:46
По поводу второго совета, мне тоже приходила идея создавать каждый раз заново QDataStream, но я собираюсь многократно (483 раза) его использовать. Как заменять объект новым не меняя имени? Нужно сначала убить старый?
Код:
for( int i= 0; i < 483; ++i )
{
QDataStream ds;
...
}


Название: Re: Вопрос по работе с QDataStream?
Отправлено: studert от Декабрь 09, 2008, 10:50
Но тогда объект будет существовать только внутри цикла, не писать же мне циклы до одного только ради того чтобы объект при завершинии одного действия уничтожился. Хотелось бы все же понять как обойтись без этого. Как все же сбросить его, не создавая заново.


Название: Re: Вопрос по работе с QDataStream?
Отправлено: BRE от Декабрь 09, 2008, 11:43
Но тогда объект будет существовать только внутри цикла, не писать же мне циклы до одного только ради того чтобы объект при завершинии одного действия уничтожился. Хотелось бы все же понять как обойтись без этого. Как все же сбросить его, не создавая заново.
Код:
QByteArray datagramIn;
QList<Data> saveData;

for( int i = 0; i < 483; ++i )
{
    QDataStream datagramInStream(&datagramIn, QIODevice::ReadOnly);
    udpSocket.readDatagram(datagramIn.data(),datagramIn.size());
    // ... обработали данные
    data = ...
    // Сохранили
    saveData.append( data );
}

Но лучше делай все асинхронно (readyRead).  :)


Название: Re: Вопрос по работе с QDataStream?
Отправлено: studert от Декабрь 09, 2008, 13:36
Похоже я неясно выразился. Сейчас я сделал вот так:
QDataStream InStream1(&data, QIODevice::ReadOnly);
получил первый пакет
udpSock.readDatagram(data.data(),data.size());
QDataStream InStream1(&data, QIODevice::ReadOnly);
InStream1>>......
получил второй пакет
udpSock.readDatagram(data.data(),data.size());
QDataStream InStream2(&data, QIODevice::ReadOnly);
InStream2>>......
получил еще пакет
udpSock.readDatagram(data.data(),data.size());
QDataStream InStreamN(&data, QIODevice::ReadOnly);
InStreamN>>......
Поскольку идет последовательная обработка нескольких пакетов разного вида их не засунешь в цикл, и пришлось наплодить переменных. Хотел обойтись одной, только не знаю как ее возвращать в начало.


Название: Re: Вопрос по работе с QDataStream?
Отправлено: BRE от Декабрь 09, 2008, 14:18
Поскольку идет последовательная обработка нескольких пакетов разного вида их не засунешь в цикл, и пришлось наплодить переменных. Хотел обойтись одной, только не знаю как ее возвращать в начало.
Так может ты немного про протокол расскажешь, хотя бы примерно.
Типа: 1 пакет - управляющий, в зависимости от типа, необходимо получить еще несколько пакетов (для одного типа - три, для другого - пять)...


Название: Re: Вопрос по работе с QDataStream?
Отправлено: Rcus от Декабрь 09, 2008, 14:22
Интересно... я думал сообщения протокола UDP называются датаграммами не просто так: UDP не дает гарантию доставки, даже гарантии очередности получения нет


Название: Re: Вопрос по работе с QDataStream?
Отправлено: BRE от Декабрь 09, 2008, 14:31
Ну чего-то человеку нужно получать/обрабатывать, поэтому самому интересно, что там эта железка шлет.


Название: Re: Вопрос по работе с QDataStream?
Отправлено: studert от Декабрь 09, 2008, 14:56
Железка - фотокамера. Она принимает каманду запрос на съемку, затем команду на отправку кадра в ПК и отправляет нужное (прописано в команде) количество пакетов (один пакет строка изображения). Самая медленная операция в ПК - перерисовка изображения, поэтому сначала принимаю весь кадр (принимаю в течение 50 мсек), затем отрисовываю и перехожу к обработке пользовательских кнопок.


Название: Re: Вопрос по работе с QDataStream?
Отправлено: BRE от Декабрь 09, 2008, 15:06
Железка - фотокамера. Она принимает каманду запрос на съемку, затем команду на отправку кадра в ПК и отправляет нужное (прописано в команде) количество пакетов (один пакет строка изображения). Самая медленная операция в ПК - перерисовка изображения, поэтому сначала принимаю весь кадр (принимаю в течение 50 мсек), затем отрисовываю и перехожу к обработке пользовательских кнопок.
Так ты от камеры принимаешь строки кадра. Почему их прием нельзя засунуть в цикл?


Название: Re: Вопрос по работе с QDataStream?
Отправлено: studert от Декабрь 09, 2008, 20:19
Тут даже считать не надо :) каждый пакет содержит номер строки. Логичным было бы дожидаться пока не получишь последнюю строку и выходить, в том то и проблема, что строки теряются, как написать правильно, чтобы этого не было не знаю.


Название: Re: Вопрос по работе с QDataStream?
Отправлено: BRE от Декабрь 09, 2008, 20:35
Тут даже считать не надо :) каждый пакет содержит номер строки. Логичным было бы дожидаться пока не получишь последнюю строку и выходить, в том то и проблема, что строки теряются, как написать правильно, чтобы этого не было не знаю.
Ну а если попробовать получать и сохранять пакеты "сырыми" данными, а после разбирать то что принял.
Количество строк известно. Что-то типа:
Код:
QList<QByteArray*> frame;
for( int line = 0; line < lineCount; ++line )
{
    QByteArray *dataIn = new QByteArray( pendingDatagramSize, 0 );
    udpSocket.readDatagram( dataIn->data(), dataIn->size() );
    frame.append( dataIn );
}
А потом спокойно разобрать все строки.


Название: Re: Вопрос по работе с QDataStream?
Отправлено: studert от Декабрь 10, 2008, 11:54
Ну а если попробовать получать и сохранять пакеты "сырыми" данными, а после разбирать то что принял.
Количество строк известно. Что-то типа:
Код:
QList<QByteArray*> frame;
for( int line = 0; line < lineCount; ++line )
{
    QByteArray *dataIn = new QByteArray( pendingDatagramSize, 0 );
    udpSocket.readDatagram( dataIn->data(), dataIn->size() );
    frame.append( dataIn );
}
А потом спокойно разобрать все строки.
У меня сделано так:

           
Код
C++ (Qt)
FrameReceiveTime.start();
while(FrameReceiveTime.elapsed() <= 100){
if(udpSocket.hasPendingDatagrams()){
QDataStream datagramInStream3(&datagramIn, QIODevice::ReadOnly);
datagramIn.resize(udpSocket.pendingDatagramSize());
udpSocket.readDatagram(datagramIn.data(),datagramIn.size());
datagramInStream3>>temp>>ReceivedFrameType>>RowNumber;
if(ReceivedFrameType == 0x44415441){
for(quint32 i=RowNumber*(WindowWidth->value()/3 + (WindowWidth->value()%3 != 0));
i<(RowNumber+1)*(WindowWidth->value()/3 + (WindowWidth->value()%3 != 0));i++)
    datagramInStream3>>monitor->Data[i];
  }
}
}
           Внутри цикла я только проверяю поле ReceivedFrameType (подходят полько пакеты с 0х44415441) и переписываю строки в соответствующие элементы массива monitor, после завершения цикла отрисовываю.
           Я попробую так как предложили вы, только внутри цикла for необходимо добавить waitForReadyRead(1), чтобы читать только при наличии пакета, но мне кажется что особого эффекта это не даст, поскольку обработка строк у меня минимальная, зато потом полученный массив снова обрабатывать (выкинуть "левые" пакеты, поменять местами согласно номерам строк) перед отрисовкой. Перепишу и сравню.


Название: Re: Вопрос по работе с QDataStream?
Отправлено: west от Декабрь 13, 2008, 01:16
Если все еще актуально:
Цитировать
Можно ли сбросить поток к началу новых данных? Или придется "ручками" побайтно разбирать QbyteArray и "раскладывать по полочкам".
QDataStream stream(.....);
 ........
надо вернуть на ноль:
 stream.device()->at(0);