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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: передать файл через QTcpSocket  (Прочитано 13332 раз)
Gomerd
Гость
« : Ноябрь 25, 2013, 15:31 »

Доброго времени суток.
Задача написать клиент-серверное приложение и передачу файла. Набрел на тему http://www.prog.org.ru/topic_17556_0.html вроде все хорошо:

Клиент:
Код:
sendFile = new QFile(ui->fileLabel->text());
    QFileInfo fileInfo(sendFile->fileName());
    QString fileName(fileInfo.fileName());

    socket->waitForConnected();

    QByteArray block;

    QDataStream read(sendFile);
    sendFile->open(QFile::ReadOnly);

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

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

    dStream << quint64(sendFile->size());
    //        dStream << CRC32(filePath);
    //        //qDebug () << "CRC sended: " << CRC32(filePath);
    //        dStream << filePath;
    //        dStream << inPath;

    socket->write(bArray);
    socket->waitForBytesWritten();

    long 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 += socket->write(ba, sizeof(char)*l);
        socket->waitForBytesWritten();

        if (-1 == lBytes){
            qWarning() << "Error";
            socket->close();

            return;
        }

    }
    free((void*)ch);

Сервер:
Код:
QTcpSocket* socket = (QTcpSocket*)sender();
    quint64 fileSize;
    QString fileName;
    QByteArray receivedLine;

    socket->waitForReadyRead(-1);

    QByteArray bArray;
    QDataStream dStream(&bArray, QIODevice::ReadWrite);
    dStream.setVersion(QDataStream::Qt_4_5);
    bArray = socket->readAll();

    dStream >> fileSize;
    dStream >> fileName;
    dStream >> receivedLine;

    QFile receivedFile("E:/test/1.txt");
    receivedFile.open(QFile::WriteOnly);
    QDataStream write(&receivedFile);
    write.setVersion(QDataStream::Qt_4_5);

    long int lBytesDone = 0;
    long int lSize = fileSize;
    long int lBytes;

    while (lBytesDone < lSize)
    {
        lBytes = 0;
        while (lBytes == 0) lBytes = socket->waitForReadyRead(-1);
        QByteArray tmp = socket->readAll();
        lBytes += write.writeRawData(tmp.data(), tmp.size());
        lBytesDone += tmp.size();
    }

    receivedFile.close();
}

Однако при получении последнего блока данных приложение зависает на этой строчке:

Код:
while (lBytes == 0) lBytes = socket->waitForReadyRead(-1);

Если передавать большой файл, то записывает все кроме последнего блока, если передается файл в пару кб то он сразу зависает.
В чем может быть проблема?
« Последнее редактирование: Ноябрь 25, 2013, 15:33 от Gomerd » Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #1 : Ноябрь 25, 2013, 15:43 »

Передаёте fileSize и данные.
Читаете fileSize, fileName, receivedLine и данные. Удивляетесь почему полученных данных меньше чем отосланных. Не удивляйтесь - они в fileName, receivedLine.
Записан
Gomerd
Гость
« Ответ #2 : Ноябрь 25, 2013, 15:54 »

Передаёте fileSize и данные.
Читаете fileSize, fileName, receivedLine и данные. Удивляетесь почему полученных данных меньше чем отосланных. Не удивляйтесь - они в fileName, receivedLine.

Потерялось в процессе ковыряния кода. Подправил как было

Клиент:
Код:
dStream << quint64(sendFile->size());
    dStream << fileName;
+ данные

сервер:
Код:
dStream >> fileSize;
    dStream >> fileName;

+данные.
Ошибка остается.
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #3 : Ноябрь 26, 2013, 15:03 »

Код:
bArray = socket->readAll();
Вот тут проверьте сколько байтов получаете.


Записан
Gomerd
Гость
« Ответ #4 : Ноябрь 26, 2013, 23:17 »

Спасибо, уже разобрался:)
Записан
felixdesouza
Гость
« Ответ #5 : Февраль 13, 2014, 17:07 »

Та же беда. Разваливается передача.
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #6 : Февраль 14, 2014, 08:21 »

Та же беда. Разваливается передача.
Группа программистов-экстрасенсов спешит вам на помощь.
Записан
felixdesouza
Гость
« Ответ #7 : Февраль 14, 2014, 09:26 »

Простите великодушно.

Отправитель:
Код:
    QFile *sendFile = new QFile(...имя файла...);
    QFileInfo fileInfo(sendFile->fileName());

    QDataStream read(sendFile);
    sendFile->open(QFile::ReadOnly);
    read.setVersion(QDataStream::Qt_5_1);

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

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

    dStream << quint64(sendFile->size());
    dStream << fileInfo.fileName();

    pSocket->write(bArray);
    pSocket->waitForBytesWritten();

    long 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 = pSocket->write(ba, sizeof(char)*l);

        pSocket->waitForBytesWritten();
        qDebug()<<"ba.size()"<<ba.size();
        if (-1 == lBytes)
        {
            qWarning() << "Error";
            pSocket->close();

            return;
        }
    }
    free((void*)ch);

    pSocket->close();

Получатель
Код:
 quint64 fileSize;
    QString fileName;

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

    pSocket.waitForReadyRead(-1);
    bArray = pSocket.readAll();

    dStream >> fileSize;
    dStream >> fileName;

    emit doUpdateUI(QString::number(fileSize));
    emit doUpdateUI(fileName);

    QFile saveFile("C:/"+fileName);
    saveFile.open(QFile::WriteOnly);
    QDataStream write(&saveFile);
    write.setVersion(QDataStream::Qt_5_1);

    long int lBytesDone = 0;
    long int lSize = fileSize;
    long int lBytes;

    while (lBytesDone < lSize)
    {
        lBytes = 0;

        while (lBytes == 0)
        {
            lBytes = pSocket.waitForReadyRead(-1);
        }
        if (-1 == lBytes)
        {//Если произошла ошибка сокета, то
            qDebug () << "EROOR!!";
            pSocket.close();
            return;
        }//if (-1 == lBytes)

        QByteArray tmp = pSocket.readAll();
        qDebug()<<"tmp.size();"<<tmp.size();

        lBytes += write.writeRawData(tmp.data(), tmp.size());
        lBytesDone += tmp.size();
    }

    saveFile.close();

Имя файла и размер доходят и читаются. А файл считывается не правильно. Видимо что-то случилось...
« Последнее редактирование: Февраль 14, 2014, 09:57 от felixdesouza » Записан
felixdesouza
Гость
« Ответ #8 : Февраль 18, 2014, 14:17 »

Та же беда. Разваливается передача.
Группа программистов-экстрасенсов спешит вам на помощь.

аууууу... Экстрасенсы....
« Последнее редактирование: Февраль 18, 2014, 14:19 от felixdesouza » Записан
Bepec
Гость
« Ответ #9 : Февраль 18, 2014, 14:20 »

А какой файл передаёте? бинарный?
Записан
felixdesouza
Гость
« Ответ #10 : Февраль 18, 2014, 14:24 »

Пробовал текстовый, zip и avi.

1 случай из 20 удачный.

Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #11 : Февраль 18, 2014, 14:39 »

Сравните их побайтно, где несовпадение.
Вижу варианты
а) bArray = pSocket.readAll(); - можете кроме длины и имени и часть файла прихватить уже.
б) pSocket->close(); - возможно сокет закрывается раньше, чем вы всё считали. Не помню точно в Qt нормально ли тут на принимающей стороне всё считаться.

Ну и вот это точно ошибка:
Код
C++ (Qt)
free((void*)ch);
Хотя к вашей проблеме едва ли относится.
Записан
felixdesouza
Гость
« Ответ #12 : Февраль 18, 2014, 14:43 »

а) bArray = pSocket.readAll(); - можете кроме длины и имени и часть файла прихватить уже.

Только что-то сюда капнул.
Убрал передачу метаданных. Передаётся и принимается правильный размер файла, т.е.  файл правильного размера. Осталось красиво его записать на диск.
Записан
felixdesouza
Гость
« Ответ #13 : Февраль 18, 2014, 15:19 »

Вроде работает.
Надо после записи метаданных flush сокету сделать на клиенте.
Спасибо.
Записан
iCast
Гость
« Ответ #14 : Декабрь 01, 2014, 01:21 »

Ребят, вот тоже взял этот код, немного убрал что не нужно, но программа уходит в вечный цикл.
Клиент отправляет файл
Код:
void MyClient::slotSendToServer()
{

        QFile *sendFile = new QFile("C:\\Users\\1\\Desktop\\2.exe");
            //QFileInfo fileInfo(sendFile->fileName());
            //QString fileName(fileInfo.fileName());

            socket->waitForConnected();

            QDataStream read(sendFile);
            sendFile->open(QFile::ReadOnly);

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

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

            dStream << quint64(sendFile->size()-sizeof(quint64));

            socket->write(bArray);
            socket->waitForBytesWritten();

            long 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 += socket->write(ba, sizeof(char)*l);
                qDebug()<<"l:" << lBytes;
                socket->waitForBytesWritten();
                if (-1 == lBytes){
                    qWarning() << "Error";
                    socket->close();

                    return;
                }

            }
             qDebug()<<"sendFile->size(): "<<sendFile->size();
            //free((void*)ch);

}
Сервер принимает
Код:
void MyServer::slotReadClient() // считывает сообщение от клиента
{
    QTcpSocket* socket = (QTcpSocket*)sender();
        quint64 fileSize;
        QString fileName;
        QByteArray receivedLine;

        socket->waitForReadyRead(-1);

        QByteArray bArray;
        QDataStream dStream(&bArray, QIODevice::ReadWrite);
        dStream.setVersion(QDataStream::Qt_4_8);
        bArray = socket->readAll();

        dStream >> fileSize;
        qDebug()<<"recive file size: "<<fileSize;

        QFile receivedFile("C:\\Users\\1\\Desktop\\folder\\2.exe");
        receivedFile.open(QFile::WriteOnly);
        QDataStream write(&receivedFile);
        write.setVersion(QDataStream::Qt_4_8);

        long int lBytesDone = 0;
        long int lSize = fileSize;
        long int lBytes;
        qDebug()<<"lSize: "<<lSize;
        while (lBytesDone < lSize)
        {
            lBytes = 0;
            while (lBytes == 0) lBytes = socket->waitForReadyRead(-1);
            QByteArray tmp = socket->readAll();
            lBytes += write.writeRawData(tmp.data(), tmp.size());
            lBytesDone += tmp.size();
            qDebug()<<"l:" << lBytesDone;
        }

        receivedFile.close();
}
Дебаг показал что здесь проблема
Код:
while (lBytes == 0) lBytes = socket->waitForReadyRead(-1);
расскажите поподробнее как происходит передача файла
и как решить проблему. После зависания я закрываю программу и вижу что клиент отправил столько:
Код:
l: 789756 
l: 789864
sendFile->size():  789864
А сервер получил столько:
Код:
l: 787710 
l: 788733
l: 788841
Программа неожиданно завершилась.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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