2013-08-18 120 views
1

在我的應用程序中,我有一種方法將文件上傳到服務器,這工作正常。QNetworkAccessManager多次上傳失敗

但是當我一次調用這個方法多次(比如迭代chooseFilesDialog的結果)前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代碼),您應該處理這些錯誤以查看上傳失敗時的實際問題,而不是猜測問題出在服務器的最大連接上。 – TheDarkKnight

+0

好吧,我把QNetworkAccesManager移到了外面再重複使用,現在上傳是一個接一個地進行的,其間有一秒左右的時間。我假設QnetworkAccessManager有某種隊列。太糟糕了,並不存在某種多重屬性。謝謝! 不維護指針?哪裏有什麼對象? (初學者與指針的概念) –

+0

任何時候你使用關鍵字'新',你應該確保你保持一個指針,並在完成它時調用'刪除'。在這種情況下,您顯示的代碼創建了名爲'nam'的QNetworkAccessManager,然後超出範圍。該對象存在,但當您不再需要該對象或程序退出時,您沒有指向調用delete的指針。同樣的規則適用於QNetworkReply對象的「回覆」,因爲它是通過調用put()創建並給予您的新對象。 – TheDarkKnight

回答

0

首先,不要創建QNetworkManager每次啓動的上傳時間。
其次,你一定要刪除你所有的東西new(),否則你會留下內存泄漏。這包括QFile,QNetworkManagerQNetworkReply(!)。
第三,你必須等待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類只是一個單身人士,那麼你不必清理。它將在應用程序退出時清除。但是,正如您所指出的那樣,始終清理分​​配的資源(或打開的文件)是一種很好的做法。你永遠不知道,在某一天,你決定動態地創建多個對象,那麼清理代碼就很好。 –