Russian Qt Forum

Qt => Работа с сетью => Тема начата: rudolfninja от Декабрь 16, 2013, 21:41



Название: Не сохраняются данные из сокета
Отправлено: rudolfninja от Декабрь 16, 2013, 21:41
Доброго времени суток. У меня вопрос до боли заезженный на этом форуме, собственно, отсюда и брал код реализации.
Проблема вот в чем. Есть клиент. Он может передавать файл ( > 100 Мб) другому клиенту. Передача происходит в отдельном потоке. Передается файл нормально, а вот собрать его не получается. Программа зависает на 99% приема.
Код обработчика на отправку файла:
Код:
void MainWindow::slot_send_file_menu_handler()
{
    QTcpServer* server_to_send = new QTcpServer(this);
    if(!server_to_send->listen(QHostAddress::Any, 1234))
        return;
    QObject::connect(server_to_send, SIGNAL(newConnection()), this, SLOT(slot_new_connection()));
}
Код:
void MainWindow::slot_new_connection()
{
    QTcpSocket* socket_to_send = ((QTcpServer*)(sender()))->nextPendingConnection();
    SendFileThread* thread = new SendFileThread();
    thread->set_params(socket_to_send, QString("d:\\work\\nets.zip"));
}
В потоке, при установке параметров поток запускается. Собственно в нем и происходит передача файла.
Код:
void SendFileThread::set_params(QTcpSocket *socket, QString path)
{
    _socket = socket;
    _path = path;
    start();
}

void SendFileThread::run()
{
    QFile file_to_send(_path);
    QDataStream read(&file_to_send);
    file_to_send.open(QFile::ReadOnly);
    QByteArray bArray;
    QDataStream dStream(&bArray, QIODevice::WriteOnly);
    dStream.setVersion(QDataStream::Qt_4_5);

    dStream << quint64(file_to_send.size());
    dStream << _path;

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

    long lBytes = 0;
    char ch[1024];
    ch[1023] = '\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();
        _socket->flush();
        if (-1 == lBytes){
            qWarning() << "Error";
            _socket->close();
            return;
        }
    }
}
Когда клиент соглашается принять файл:
Код:
void MainWindow::slot_info_menu_handler()
{
    QTcpSocket* socket = new QTcpSocket(this);
    socket->connectToHost("172.16.252.174", 1234);
    QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(slot_read_client()));
}
Ну и функция приема:
Код:
QTcpSocket* _socket = ((QTcpSocket*)sender());
    quint64 fileSize;
    QString getedFilePath;
    QString usedFilePath;
    _socket->waitForReadyRead(-1);
    QByteArray bArray;
    QDataStream dStream(&bArray, QIODevice::ReadWrite);
    dStream.setVersion(QDataStream::Qt_4_5);
    bArray = _socket->readAll();
    dStream >> fileSize;
    qDebug () << "fileSize" << fileSize;
    dStream >> getedFilePath;
    qDebug () << "getedFilePath" << getedFilePath;
    usedFilePath = getedFilePath;
    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){
        lBytes = 0;
        while (lBytes == 0)
            lBytes = _socket->waitForReadyRead(-1);
        if (!lBytes){
            qWarning("-----TFileServer: Aborting download.");
            _socket->close();
            return;
        }
        QByteArray tmp = _socket->readAll();
        lBytes += write.writeRawData(tmp.data(), tmp.size());
        lBytesDone += tmp.size();
        float procentage = ((float)lBytesDone / fileSize) * 100;
        qDebug () << procentage;
    }
    save.close();
    qDebug () << "File saved";
Но файл передается не полностью, программа зависает на 99%.
Подскажите, пожалуйста, в чем может быть проблема и как ее решить?
Спасибо.


Название: Re: Не сохраняются данные из сокета
Отправлено: Fregloin от Декабрь 17, 2013, 11:17
проблема в неправильном подходе. вообще если вы решили использовать QDataStream посмотрите пример FortuneServer. Во вторых, данные могут приходить произвольными порциями,а не по 1023 байта как выхотите. Слать сначала размер и название файла и ожидать что после все данные будут идти равными порциями не стоит. По хорошему нужно слать какой то заголовок (структуру), в которой передавать размер и прочую полезную инфу, далее читать данные с сокета и проверять что данные пришли все. А еще лучше в конце тоже слать какойто признак, что данных больше нет. Вот после прочения этого признака конца нужно делать что файл принят целиком. Ну и таймауты приема желательно использовать тоже, т.к. в зависимости от состояния сети и ее топологии данные могут блуждать долго или вообще теряться (например плохое соединение и данные приходят обрывками). Можно еще как делать, слать порцию данных, а в ответ слать отвкет - принято столькото байт, и пока не пришел ответ от клиента, нет нужды слать следующую часть. Передача конечно заметлится, зато достоверность повысится.


Название: Re: Не сохраняются данные из сокета
Отправлено: rudolfninja от Декабрь 17, 2013, 12:02
По хорошему нужно слать какой то заголовок (структуру), в которой передавать размер и прочую полезную инфу, далее читать данные с сокета и проверять что данные пришли все. А еще лучше в конце тоже слать какойто признак, что данных больше нет. Вот после прочения этого признака конца нужно делать что файл принят целиком.
А можете написать небольшой пример всего этого?


Название: Re: Не сохраняются данные из сокета
Отправлено: Fregloin от Декабрь 18, 2013, 11:38
Ну вы же программист или кто? )
У меня конкретного примера как я написал выше нет, могу скинуть пример сокета, который читает json пакеты. Не знаю, поможет ли в вашем случае, но впринципе идея там похожа на ту что я указывал выше.


Название: Re: Не сохраняются данные из сокета
Отправлено: rudolfninja от Декабрь 18, 2013, 15:01
Получается, что я =)
Спасибо, гляну.
Я делал аналогично этому: http://www.prog.org.ru/topic_10870_15.html (прием и отправку). Удивляет то, что там у людей все работает, а у меня нет =)