2014-05-16 156 views
1

我目前正面臨一個關於QFtp的奇怪問題。我想從FTP服務器上下載一堆文件,但是當我下載到y文件後,執行了ftp->get()命令後,文件被填充,但沒有發出SIGNALcommandFinished(),因此它不會下載其他文件。QFtp獲取從不發射commandFinished()

這裏是我的代碼:

void Ftp::commandFinished(int i, bool error) 
{ 

    if(ftp->currentCommand() == QFtp::Get) 
    { 
     if(error) 
     { 
      //blablabla-ERROR-blablabla 
     } 
     currentFile->close(); 
     filesToDownload.pop_front(); 
     processFileList(); 
    } 

    /**Gestion de la commande Login (authentification de l'utilisateur) 
    */ 
    if(ftp->currentCommand() == QFtp::Login) 
    {//not utile here} 

    /**Gestion de la commande ConnectToHost (connexion au serveur) 
    */ 
    if (ftp->currentCommand() == QFtp::ConnectToHost) 
    {//not utile here} 

    /**Gestion de la commande List (téléchargement d'un fichier) 
    */ 
    if(ftp->currentCommand() == QFtp::List) 
    { 
     if(error) 
     { 
      //Nananana-FAIL-nanana 
     } 

     //!Tri des fichiers à télécharger en fonction de leur dernière date de modification 
     if (!filesToDownload.isEmpty()) 
     { 
      currentPeripheral->setLastDownloadDate(newLastModifiedDate) ; 
      std::sort(filesToDownload.begin(),filesToDownload.end(),compareQUrlInfos); 
      processFileList(); 
     } 



    } 
} 

void Ftp::processFileList() 
{ 

QUrlInfo info; 

if (filesToDownload.isEmpty()) 
{ 
    //!Suicide de l'instance de Ftp 
    ftp->close(); 
    disconnect(this,0,0,0); 
    this->deleteLater(); 
    return ; 
} 

info = filesToDownload.first(); 
QDir dlDir(QString::number(currentPeripheral->getId())); 

//!Si un fichier a été téléchargé, on déclenche son traitement 
if (currentFile != nullptr) 
{ 
    emit(oneDownloadFinished(currentFile->fileName(),currentPeripheral)); 
    delete currentFile; 
    currentFile = nullptr; 
} 

//!On crée un répertoire de téléchargement si nécessaire 
if (!dlDir.exists()) 
{ 
    dlDir.mkdir("."); 
} 

//!on crée le fichier qui contiendra le téléchargement 
currentFile = new QFile(dlDir.filePath(info.name())); 

if(!currentFile->open(QIODevice::WriteOnly)) 
{ 
    delete currentFile; 
    currentFile = nullptr; 
    emit(writeToMonitoringConsole(QString("Erreur lors de la creation du fichier "+info.name()),"Error")); 
    return; 
} 


//Here I start (sometimes) a never ending fail 
ftp->get(info.name(), currentFile); 
} 

起初我還以爲是因爲我做了太多的要求,而我被拒絕,因爲這一點,但即使有Sleep(2000)它塊。封鎖出現得更快。我通常可以下載大約30個文件(當幸運70時,一旦我設法有200個!)。用Sleep(2000)我幾乎沒有成功下載2-3個文件。

這是我的錯嗎? QFtp有沒有限制我沒有找到?或者是其他東西 ?

編輯:我測試了薩姆的事情,因爲我張貼,什麼是驚人的,監測dataTransferProgress()信號時,其是有問題的文件被完全下載(qDebug說:「88928分之88928」),但我從來沒有輸入commandFinished()。

我插槽commandFinished()鏈接到我的QFtp :: commandFinished信號是這樣的:

connect(ftp, SIGNAL(commandFinished(int,bool)), this, SLOT(commandFinished(int,bool))); 
+0

我沒有看到你的代碼中的任何commandFinished信號檢查?你能分享更多的代碼嗎? – lpapp

+0

當一個命令完成時,commandFinished()由QFtp發出,我通常不應該自己發送這個信號。 [Qt commmandFinished](http://qt-project.org/doc/qt-4.8/qftp.html#commandFinished) – Karalix

+0

這可能是https://bugreports.qt.io/browse/QTBUG-19409 – x29a

回答

3

我看到幾乎同樣的事情,與FTPWidget類別I從未收到commandFinished了GET請求。 dataTransferProgress()信號可靠地報告100%下載及其全部。

我周圍使用設置超時如下黑客攻擊:其中定時器連接到修正常規

// Set up a single shot QTimer and connect it to a function to fix things 

connect(m_lostFinishedTimer, SIGNAL(timeout()), this, SLOT(lostFinishedHack())); 

// Start the timeout when the download data progress hits 100% 

void FtpWidget::updateXferProgress(qint64 readBytes, qint64 totalBytes) 
{ 
    m_progressBar->setValue(progress_value(readBytes, totalBytes)); 

    if (m_downloading && readBytes == totalBytes) 
     m_lostFinishedTimer->start(); 
} 

// And don't forget to stop the timer if you do get a finish: 

void FtpWidget::commandFinished(int id, bool error) 
{ 
    QFtp::Command cmd = m_ftp->currentCommand(); 
    // ... 
    if (cmd == QFtp::Get) 
    { 
     m_lostFinishedTimer->stop(); 
     //.... 
    } 
    // ... 
} 

基本上關閉下載文件,將服務器重新連接,並移動到下一個文件

void FtpWidget::lostFinishedHack() 
{ 
    if (!m_downloading) 
     return; 

    if (m_downloadFile) 
    { 
     DOUT("FtpWidget::lostFinshedHack() -- file: " << DS(m_downloadFile->fileName()) << "\n"); 
     m_downloadFile->close(); 
     delete m_downloadFile; 
     m_downloadFile = 0; 
    } 

    // just reconnect the thing 
    Connect(m_ftpServerName->text()); 

    downloadNextFile(); 
} 

這似乎工作得很好,雖然我使用了一個更大的超時。

因此,當我在工作到位後,我回過頭去看QFtp內部發生了什麼。使用調試器在斷點處添加一個打印命令,我可以看到來自該文件的原始回覆。似乎正在發生的事情是,我正在使用的ftp服務器在某個時間以不同的順序發送它的ftp回覆。

當我的作品我跟蹤的樣子:

FtpWidget::commandStarted(id: 265) -- Get 
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 200, text "Operation successful" 
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 213, text "135980" 
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 200, text "Operation successful" 
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 150, text "Opening BINARY connection for 000-23Sep2014_103527.jpg (135980 bytes)" 
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 226, text "Operation successful" 
FtpWidget::commandFinished(id: 265, error: 0) -- Get 

FtpWidget::commandStartedcommandFinished是我的插槽,_q_piFtpReply()是QFtp對象的私處,我已經勾我的跟蹤斷點。

當它失敗時,我得到:

FtpWidget::commandStarted(id: 256) -- Get 
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 200, text "Operation successful" 
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 213, text "135896" 
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 200, text "Operation successful" 
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 150, text "Opening BINARY connection for 000-23Sep2014_103525.jpg (135896 bytes)" 
FtpWidget::lostFinshedHack() 
FtpWidget::lostFinshedHack() -- file: C:/Users/sean/Temp/Snapshots5/000-23Sep2014_103525.jpg 
FtpWidget::connect("ftp://[email protected]/") 

獲取150回覆代碼200響應代碼後,似乎是這個問題。所以,如果你去查看FTP的回覆codes並查看qftp.cpp,看起來有150個到達之後,150導致qftp實現狀態機進入永久等待狀態。據我可以告訴它的我的FTP服務器是搞亂了不是qftp.cpp(也許我應該嘗試電匯鯊魚確保)。

現在我堅持我的超時解決方法的問題。

+0

我我試圖破解它,但我沒有得到足夠的可靠性。我嘗試重新連接時失敗,但最終我在ftp服務器上同時連接了很多不能被我關閉的連接。所以我決定放棄在我的FTP操作中使用Qt。 我用它代替了[FTP客戶端類](http://www.codeproject.com/Articles/8667/FTP-Client-Class),它非常易於使用且可靠。 – Karalix

2

我來不及回覆,但它仍然可以幫助別人。

void Ftp::commandFinished(int i, bool error)它始終是更好地檢查QFtp::None選項也, 因爲如果你的最後一個命令是getcommandFinished()插槽被調用,然後 if (ftp->currentCommand() == QFtp::Get)將無法​​識別的最後一個命令,因爲當前的命令可能不因爲它已經完成,所以是get

您還可以使用ID 爲if(ftp->currentCommand() == QFtp::Get || 1 == id)

+0

感謝您的回覆,我現在無法再訪問有問題的代碼,因此我無法測試您的建議,我希望這會對其他人有所幫助! – Karalix