I am currently facing a weird problem concerning QFtp. I want to download a bunch of files from a FTP server but when I come to some point, after downloading x files on y, the ftp->get()
command is done, the file is filled, but there is no emission of the SIGNAL
commandFinished()
and thus it does not download the other files.
Here is my code :
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);
}
At first I thought it was because I was making too much request and that I was rejected because of that, but even with a Sleep(2000)
it blocks. The blocking appears even more quickly. I usually can download around 30 files (when lucky 70, once I managed to have 200 !). With Sleep(2000)
I barely succed to download 2-3 files.
Is it a mistake from me ? Is there a limitation in QFtp I didn't found ? Or something else ?
EDIT : I tested somes things since I posted it, and what was striking, when monitoring the dataTransferProgress() signal, is that the problematic file is fully downloaded (qDebug says "88928/88928") but I never enter commandFinished().
My slot commandFinished() is linked to my QFtp::commandFinished SIGNAL this way :
connect(ftp, SIGNAL(commandFinished(int,bool)), this, SLOT(commandFinished(int,bool)));
I'm seeing pretty much the same thing, with an
FTPWidget
class I use never receiving acommandFinished
for a GET request. The dataTransferProgress() signal reliably reports 100% downloaded and its all there.I've hacked around using a setting a timeout as follows:
where the timer is connected to a fixup routine basically close the download file, reconnect the server, and move on to the next file
This seems to work well enough, though I'm using a rather larger timeout.
So a while after I got that work around in place, I went back and looked at what's going on inside the QFtp itself. Using the debugger to add a print command on a breakpoint I can see the raw replies from the. What seems to be happening is that the ftp server I'm using is sending its ftp replies in a different order sometime.
When it works I my trace looks like:
Where the
FtpWidget::commandStarted
andcommandFinished
are my slots, and the _q_piFtpReply() is a private part of the QFtp object where I've hook my tracing breakpoint.When it fails I get:
Getting the 150 reply code after the 200 reply code seems to be the problem. So if you go look up the FTP reply codes and look through the qftp.cpp it looks having the 150 arrive after the 150 is causing the qftp implementation state machine to go into a perpetual wait. As far as I can tell its my ftp server that is messing things up not the qftp.cpp (maybe I should try wire shark to make sure).
For now I'm sticking to my timeout workaround for the problem.