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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Разбивка файла при передаче по QTcpSocket  (Прочитано 8550 раз)
ManOfOrange
Гость
« : Апрель 06, 2011, 10:25 »

Приветствую всех :-)

Передаю по сети файлы, используя QTcpSocket и многопоточность. Соответственно, файл перед отправкой надо разбить на кусочки, на получателе - собрать.
Нашёл тему - http://www.prog.org.ru/topic_10870_0.html, где уже есть прекрасные готовые куски.
Для разбивки использовал код от BRE (спасибо :-), что на второй странице; для сборки - код от TukiNov (тоже спасибо :-)
В итоге, у меня это выглядит так:

Разборка и отправка:
Код:
void threadClient::run()
{
    //qDebug () << "threadClient::run()";
    QTcpSocket tcpSocket;

    if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
        //qDebug () << "error(tcpSocket.error())";
        return;
    }
    tcpSocket.waitForConnected();

    QByteArray block;
    
    QFile file(filePath);
    QDataStream read(&file);
    file.open(QFile::ReadOnly);

    //отправка служебной информации

    QByteArray bArray;
    QDataStream dStream(&bArray, QIODevice::WriteOnly);
    dStream.setVersion(QDataStream::Qt_4_5);

    dStream << quint64(file.size());
    dStream << CRC32(filePath);
    //qDebug () << "CRC sended: " << CRC32(filePath);
    dStream << filePath;
    dStream << inPath;

    tcpSocket.write(bArray);
    tcpSocket.flush();
  
    ong int lBytes = 0;
    char ch [1024];
    ch[1023] = '\0';
    int i=0;
    while(!read.atEnd()){
      int l = read.readRawData(ch, sizeof(char)*1023);
      QByteArray ba(ch, sizeof(char)*l);

      lBytes += tcpSocket.write(ba, sizeof(char)*l);
      
//!!Вот этот qDebug
      qDebug () << "block.size: " << i;
      i++;
//!!

      tcpSocket.flush();

      if (-1 == lBytes){
        qWarning() << "Error";
        tcpSocket.close();

        return;
      }
      float procentage = ((float)lBytes / file.size()) * 100;
      emit setProcentage((int)procentage);
    }//while(!readEnd())
    free((void*)ch);

Приём и сборка:
Код:
void FortuneThread::run()
{
    qDebug () << "FortuneThread::run()";
    QTcpSocket tcpSocket;

    if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
        emit error(tcpSocket.error());
        return;
    }

    quint64 fileSize;
    quint32 CRCgeted;
    QString getedFilePath;
    QString usedFilePath;

    tcpSocket.waitForReadyRead(-1);

    QByteArray bArray;
    QDataStream dStream(&bArray, QIODevice::ReadWrite);
    dStream.setVersion(QDataStream::Qt_4_5);

    bArray = tcpSocket.readAll();
    dStream >> fileSize;
    qDebug () << "fileSize" << fileSize;
    dStream >> CRCgeted;
    qDebug () << "CRCgeted" << CRCgeted;
    dStream >> getedFilePath;
    qDebug () << "getedFilePath" << getedFilePath;
    dStream >> usedFilePath;
    qDebug () << "usedFilePath" << usedFilePath;

    //Приём и сборка файла

    QFile save(usedFilePath);
    save.open(QFile::WriteOnly);
    QDataStream write(&save);
    write.setVersion(QDataStream::Qt_4_5);

    long int lBytesDone = 0; //Пока ничего не приняли
    long int lSize = fileSize;
    qDebug () << "lSize" << lSize;
    long int lBytes;

    while (lBytesDone < lSize){//Пока приняли меньше, чем указано
        //Ожидаем данные
        //qDebug () << "In while";
        lBytes = 0;
        while (lBytes == 0) lBytes = tcpSocket.waitForReadyRead(-1);
        //qDebug () << "tcpSocket readyread";

        if (-1 == lBytes){//Если произошла ошибка сокета, то
            qWarning("-----TFileServer: Aborting download.");
            //qDebug () << "EROOR!!";
            tcpSocket.close();
            return;
        }//if (-1 == lBytes)

        QByteArray tmp = tcpSocket.readAll();
        lBytes += write.writeRawData(tmp.data(), tmp.size());
        //qDebug () << "lBytes: " << lBytes;
        lBytesDone += tmp.size();
        //qDebug () << "lBytesDone" << lBytesDone;
        float procentage = ((float)lBytes / fileSize) * 100;
        //qDebug () << "procentage" << procentage;
        //emit setProcentage((int)procentage);
        }//while (lBytesDone < lSize)
    save.close();
    qDebug () << "File saved";

    exec();
}

На маленьких файлах (до мегабайта) всё работает прекрасно. При попытке передать файл в мегабайт - файл записан не полностью.
Тогда я вставил строчки:
Код:
qDebug () << "block.size: " << i;
i++;
Просто для того, чтобы проверить, всё ли записывается на отправителе.

И оно заработало.

Если закомментить qDebug - не работает. Если просто выводить "blockSize" без i - не работает.
Если оставить - всё прекрасно передаётся (пробовал на файлах в 700 мегов включительно).
Объяснить это кроме как It's magic! я не могу. разве что, qDebug даёт какую-то минимальную задержку, которая нужна tcpSocket'у для write перед flush...

Так что, оно, конечно, сейчас работает, но является, несомненно, невероятным костылём.

Не подскажете ли, в чём именно дело (ну оооочень интересно) и как костыль убрать.

Заранее спасибо :-)
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Апрель 06, 2011, 10:28 »

Делай bool QAbstractSocket::waitForBytesWritten ( int msecs = 30000 ) [virtual] в передатчике.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
ManOfOrange
Гость
« Ответ #2 : Апрель 06, 2011, 11:18 »

О, заработало корректно :-)
Спасибо большое :-)

то есть, сокет просто не успевал write?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #3 : Апрель 06, 2011, 11:23 »

Да. А  flush можешь убрать, он тут не нужен.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
ManOfOrange
Гость
« Ответ #4 : Апрель 06, 2011, 11:38 »

Ок, спасибо за разъяснение :-)
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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