2013-08-18 1 views
1

В моем приложении у меня есть способ загрузить файлы на сервер, это отлично работает.Ошибка многократных закачек QNetworkAccessManager

Но когда я вызываю этот метод несколько раз подряд (как итерация по результату selectFilesDialog), первые 7 (более или менее) файлов загружаются правильно, остальные никогда не загружаются.

Я думаю, что это должно быть связано с тем, что сервер не позволяет больше, чем X-соединений из одного источника, может быть?

Как я могу убедиться, что загрузка ждет бесплатного установленного соединения?

это мой метод:

QString Api::FTPUpload(QString origin, QString destination) 
{ 
    qint64 timestamp = QDateTime::currentMSecsSinceEpoch(); 
    QUrl url("ftp://ftp."+getLSPro("domain")+destination); 
    url.setUserName(getLSPro("user")); 
    url.setPassword(getLSPro("pwd")); 

    QFile *data = new QFile(origin, this); 
    if (data->open(QIODevice::ReadOnly)) 
    { 
     QNetworkAccessManager *nam = new QNetworkAccessManager(); 
     QNetworkReply *reply = nam->put(QNetworkRequest(url), data); 
     reply->setObjectName(QString::number(timestamp)); 
     connect(reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(uploadProgress(qint64, qint64))); 

     return QString::number(timestamp); 
    } 
    else 
    { 
     qDebug() << "Could not open file to FTP"; 
     return 0; 
    } 
} 

void Api::uploadProgress(qint64 done, qint64 total) { 
    QNetworkReply *reply = (QNetworkReply*)sender(); 
    emit broadCast("uploadProgress","{\"ref\":\""+reply->objectName()+"\" , \"done\":\""+QString::number(done)+"\", \"total\":\""+QString::number(total)+"\"}"); 
} 
+1

Вы создаете новый QNetworkAccessManager для каждого загружаемого файла. Это не обязательно; вам нужен только один. Кроме того, поскольку вы не поддерживаете указатель на объект, вы также будете пропускать память. Также обратите внимание, что ответ QNetwork имеет ошибку сигнала (QNetworkReply :: NetworkError code), которую вы должны обрабатывать, чтобы увидеть, какова фактическая проблема при загрузке, а не гадать, что проблема связана с максимальными соединениями сервера. – TheDarkKnight

+0

Хорошо, я переместил QNetworkAccesManager снаружи и повторно использовал то же самое, теперь закачки выполняются один за другим со вторым или около того между ними. Я предполагаю, что у QnetworkAccessManager есть какая-то очередь. Слишком плохо, что не существует какого-либо множественного свойства сразу. Благодаря! Не поддерживать указатель? где какой объект? (Im beginner with the concept of pointers) –

+0

Каждый раз, когда вы используете ключевое слово 'new', вы должны следить за тем, чтобы вы поддерживали указатель на него и вызывали «delete», когда вы закончили с ним. В этом случае отображаемый код создавал QNetworkAccessManager с именем «nam», который затем выходит за рамки. Объект существует, но у вас нет указателя на вызов delete, когда вам больше не нужен объект или когда программа завершает работу. Те же правила применяются к объекту QNetworkReply «reply», так как это новый объект, созданный и предоставляемый вам вызовом put(). – TheDarkKnight

ответ

0

Во-первых, не создают QNetworkManager каждый раз, когда вы запускаете загрузку.
Во-вторых, вам обязательно нужно удалить все, что вы new(), иначе вы останетесь с утечками памяти. Сюда входят QFile, QNetworkManager И QNetworkReply (!).
В-третьих, вам нужно подождать сигнала finished().

Api::Api() { //in the constructor create the network access manager 
    nam = new QNetworkAccessManager() 
    QObject::connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*))); 
} 

Api::~Api() { //in the destructor delete the allocated object 
    delete nam; 
} 

bool Api::ftpUpload(QString origin, QString destination) { 
    qint64 timestamp = QDateTime::currentMSecsSinceEpoch(); 
    QUrl url("ftp://ftp."+getLSPro("domain")+destination); 
    url.setUserName(getLSPro("user")); 
    url.setPassword(getLSPro("pwd")); 

    //no allocation of the file object; 
    //will automatically be destroyed when going out of scope 
    //I use readAll() (see further) to fetch the data 
    //this is OK, as long as the files are not too big 
    //If they are, you should allocate the QFile object 
    //and destroy it when the request is finished 
    //So, you would need to implement some bookkeeping, 
    //which I left out here for simplicity 
    QFile file(origin); 
    if (file.open(QIODevice::ReadOnly)) { 
     QByteArray data = file.readAll(); //Okay, if your files are not too big 
     nam->put(QNetworkRequest(url), data); 
     return true; 

     //the finished() signal will be emitted when this request is finished 
     //now you can go on, and start another request 
    } 
    else { 
     return false; 
    } 
} 

void Api::finished(QNetworkReply *reply) { 
    reply->deleteLater(); //important!!!! 
} 
+0

Спасибо, это понятно. просто для того, чтобы понять это правильно: только в этом сценарии, когда класс Api «один раз запускается для всей жизни приложения», мне нужен полный деструктор? поскольку деструктор никогда не будет называться .. (Или я совершенно не прав?) Когда приложение закрывается, ОС очищает все, что остается? Я знаю, что это лучшая практика, но, как я уже сказал, просто для понимания поведения ОС. –

+0

Если класс Api - это просто синглтон, тогда вам не нужно очищать. Он будет очищен, когда приложение выйдет. Но, как вы указываете, рекомендуется всегда очищать ресурсы, которые вы выделяете (или файлы, которые вы открываете). Вы никогда не знаете, что в один прекрасный день вы решите динамически создать более одного объекта, тогда хорошо иметь код очистки. –

 Смежные вопросы

  • Нет связанных вопросов^_^