Russian Qt Forum
Ноябрь 22, 2024, 20:16 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QByteArray и QTcpSocket  (Прочитано 10785 раз)
QabaT
Гость
« : Октябрь 01, 2006, 19:41 »

функция передачи данных по сети:
Код:

void MyClass::sendDataToSocket(const QString &header, const QVariant &data){
   if (! ( state() == QAbstractSocket::UnconnectedState  ) )   {
    QByteArray block;
    QDataStream out(&block, QIODevice::ReadWrite);
    out.setVersion(QDataStream::Qt_4_1);
    out << quint16(0);
    out << header;    
    out << data;
    out.device()->seek(0);
    out << quint16(block.size() - sizeof(quint16));
   write(block);
}//void sendData

проблема в следующем: при передаче данных типа QString на серверную часть приложения все приходит. если же передавать данные типа QByteArray, то ничего не происходит, на сервер приходит пакет нулевой длины. подскажите, пожалуйста, где "копать"???
Записан
Dendy
Гость
« Ответ #1 : Октябрь 02, 2006, 15:03 »

Напиши, как тьІ читаешь данньІе из сокета. Возможно, с QString тебе просто повезло. Дело в том, что Tcp гарантирует порядок принятия двнньІх, но не гарантирует их неразрьІвность. Всё, что тьІ принимаешь нужно дописьІвать во внутренний буфер, и если его размер получается больше, чем записанньІе первьІе твои два байта (размер блока) - натравляешь QDataStream на осташуюся часть. QDataStream может работать только с полностью считанньІм блоком данньІх, он не возвращает данньІе в поток, например, с помощью QIODevice::ungetch(). А если данньІе бьІли считанньІ не все - он возвращает значение по умолчанию, в данном случае - пустой QByteArray() и вьІставляет свой статус в: QDataStream::status() == QDataStream::ReadPastEnd.

Никогда не помешает логировать всё, что тьІ отправляешь и принимаешь. Так бьІстрее найдёшь причину.
Записан
QabaT
Гость
« Ответ #2 : Октябрь 02, 2006, 19:31 »

функция чтения данных из сокета (серверная часть):
Код:

void Server::getDataFromSocket(){
  QDataStream in(this);
  QString header;
  QVariant data;
  in.setVersion(QDataStream::Qt_4_1);
  logFile.writeString("[thread] - new data recieved");
  forever {
    if (nextBlockSize == 0) {
      if (bytesAvailable() < sizeof(quint16)) break;
      in >> nextBlockSize;
    }
    if (bytesAvailable() < nextBlockSize)      break;
      in >> header;
      in >> data;
      logFile.writeString( "[thread] - received header " + header + data.toString());      
      nextBlockSize = 0;
  }
}

так и делаю, как видите, смотрел по примерам... натравливаю на QDataStream, но видно как-то неверно... судя из предыдущего поста, можно предположить, что QDataStream и вправду принимает не все данные. почему - мне не понятно. лог ведется - записывается заголовок пакета.
естественно, этот класс - потомок от QTcpSocket, и сингал readyRead() связан со слотом, код которого приведен выше. а в целом общая задача довольно обычна и я - не первый, кто сталкиваетсяь с ней: как же все-таки передать двоичные данные (в данном случае изображения) по сети от клиента серверу  Улыбающийся  :?: .
Записан
Mikhail
Программист
*****
Offline Offline

Сообщений: 587


Просмотр профиля
« Ответ #3 : Октябрь 02, 2006, 19:59 »

Проверь, что ты передаешь данный. Для начала в твоем коде block не инициализирован данными. Может ты и не передаешь ничего.
Кроме того, при передаче двоичных данных надо передавать именно двоичные данные. По аналогии с QString не пройдет, так как это не двоичные данные. Передачу подготовленного байтового массива лучше всего передавать, последовательно посылая в поток байты этого массива.
Чтение вести с помощью readBlock.
Записан
Dendy
Гость
« Ответ #4 : Октябрь 02, 2006, 21:00 »

Всё оказалось как я и говорил. Проверь QDataStream::status() после чтения данньІх, наверняка его значение не равно QDataStream::Ok.

Класс потока данньІх - специализированньІй инструмент для работьІ с полностью считанньІми данньІми. Например, с файлом или буфером в памяти.

В случае же сокета поток данньІх у тебя: Sequental - разделённьІй. То-есть не факт, что следующий read() из него вернёт то, что тьІ отсьІлал - оно могло ещё не прийти.

Решение - использовать кольцевой буффер для временного хранения считанньІх данньІх:

Код:
void Server::getDataFromSocket()
{
  ring_buffer << readAll();
forever
{
  if ( ring_buffer.size() < sizeof(quint16) )
    return;
  QDataStream stream( &ring_buffer );
  quint16 size;
  stream >> size;
  if ( ring_buffer.size() < size + sizeof(quint16) )
    return;
  // read useful data
  stream.close();
  ring_buffer.remove( 0, sizeof(quint16) + size );
}
}
Записан
QabaT
Гость
« Ответ #5 : Октябрь 02, 2006, 21:15 »

данные есть - фактическим параметром data является QByteArray(иQImage, перегнанный через метод save в QBuffer, ассоциированный с этим QByteArray). спасибо за совет с readBlock() (точнее readData()) - поиграюсь с ними. если что получится, сообщу...
Записан
bigirbis
Гость
« Ответ #6 : Октябрь 03, 2006, 08:55 »

ИМХО, можно еще буфер чтения сделать более глобальным и читать туда данные, покуда не достигнет определенного размера...
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.051 секунд. Запросов: 22.