QFtp & QTimer timeout on connectToHost issues (Qt 5.5.1 Win32 VS2013)



  • Hello! Got some issues using QFtp. I try to write reliable code to timeout a QFtp connectToHost and loop. The main issue here is the timeout works but the QFtp class is sort of locked and the program does not crash (instantly) but on app close the exits code is 255 instead of 0.

    // FTP
    ftp = new QFtp(this);
    connect(ftp, SIGNAL(listInfo(QUrlInfo)), this, SLOT(getListInfo(QUrlInfo)));
    connect(ftp, SIGNAL(done(bool)), this, SLOT(isDone(bool)));
    
    // timer
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(ftpTimeout()));
    
    // loop
    loop = new QEventLoop(this);
    

    The FTP:

    void ftpTest::isDone(bool)
    {
        if(ftp->error())
        {
            qDebug() << "Error: " << ftp->error();
            qDebug() << "ErrorString: " << ftp->errorString();
        }
    
        if(timer->isActive())
        {
            timer->stop();
        }
    }
    

    For the timer:

    void ftpTest::ftpTimeout()
    {
        ftp->abort();
        ftp->deleteLater();
        loop->exit(0);
    	
        qDebug() << "ftpTimeout";
    }
    

    To get the dir listing:

    loop->connect(ftp, SIGNAL(done(bool)), loop, SLOT(quit()));
    
    timer->setSingleShot(1);
    timer->start(5000);
    
    ftp->connectToHost(Host, Port);
    ftp->login(Username, Password);
    ftp->cd(Path);
    ftp->list();
    ftp->close();
    
    loop->exec();
    

    Any ideas what i did wrong here?
    Thanks!



  • Hi @qDebug,

    First up, if this is new code, you probably shouldn't be using QFtp...

    Qt 5 / C++ API changes / Changes to Qt Network says:

    The QFtp and QUrlInfo classes are no longer exported. Use QNetworkAccessManager instead. Programs that require raw FTP or HTTP streams can use the Qt FTP and Qt HTTP compatibility add-on modules that provide the QFtp and QHttp classes as they existed in Qt 4.

    So I'd recommend re-factoring to use QNetworkAccessManager instead, if this is the early stages of a new project (unless you need that "raw FTP" access). Perhaps have a read of High Level Network Operations for HTTP and FTP, if you haven't already.

    As for your code above, why are you creating your own QEventLoop? You shouldn't need to for most use cases. Simply rely on the application's loop instead, like:

    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
    
        // some of your code.
    
        connect(ftp, SIGNAL(done(bool)), app, SLOT(quit()));
    
        // more of your code.
    
        return app.exec();
    }
    

    Cheers.



  • @Paul-Colby Hi!

    Well, i use QFtp because i need the directory listing form the FTP server. As far as i know QNetworkAccessManager does only support put and get, but no listings, cd or any other FTP commands. And QNetworkAccessManager does not support a blind shot "ftp://user:pass@127.0.0.1:21/download all files in some dir/*".

    I create my own loop because i have to. I loop through a lot of data and the only way i know to wait for the next is to connect to a loop so not 1.000.0000 connections will be created at the same time. If there is any better way, please correct me.

    for(a lot of data)
    {
    loop->connect(ftp, SIGNAL(done(bool)), loop, SLOT(quit()));
    
    timer->setSingleShot(1);
    timer->start(5000);
    
    ftp->connectToHost(Host, Port);
    ftp->login(Username, Password);
    ftp->cd(Path);
    ftp->list();
    ftp->close();
    
    loop->exec();
    }
    


  • @qDebug said:

    Well, i use QFtp because i need the directory listing form the FTP server. ... And QNetworkAccessManager does not support a blind shot "ftp://user:pass@127.0.0.1:21/download all files in some dir/*".

    Fair enough :)

    I create my own loop because i have to. I loop through a lot of data and the only way i know to wait for the next is to connect to a loop so not 1.000.0000 connections will be created at the same time.

    To avoid creating too many requests, rather than trying to use an explicit even loop, I'd:
    1 connect a slot to the QFtp::commandFinished signal;
    2 just loop through just the first n items (eg the first 5) of "a lot of data";
    3 in the slot you connected in step #1, check if the command was QFtp::list, if so, repeat step #2 for the next one item.

    Does that makes sense?

    Cheers.



  • @Paul-Colby

    The loop is not my problem, there is about 2000 lines of code behind it, the loop works. I would really appreciate if we can focus on the timeout problem. Because the timeout handling will still be broken whatever i do with loops. I did test it with or without my own loop, it does not timeout if the server is reachable but the ftp is not (in some cases). I know that because i added the loop later.


  • Lifetime Qt Champion

    Hi,

    Just to be sure we all use the same stuff. Where did you get QFtp from ?





  • After i call ftp->deleteLater(); i can't use ftp anymore. If i try to ftp = new QFtp(this); again, the app crashes even when i do a delete ftp; first. And without deleteLater the class is stuck at ftp state 2 (connecting).



  • Well, the solution is pretty simple. After deleteLater the ftp object gets deleted. That is not what i want but a simple ftp = new QFtp(this); does solve this. Of course the slots need to be connected again but thats it.


  • Lifetime Qt Champion

    You do realize that you have a leak there. Even if the objects will be deleted once the parent itself is deleted, you are currently filling your memory with QFtp objects.



  • Did not notice any memory leak yet and i did open a lot of connections (about 80).

    ftp->abort();
    ftp->close();
    ftp->deleteLater();
    delete ftp;
    

    What solution to my problem would you suggest?


  • Lifetime Qt Champion

    My bad, from your last post, I understood that you replaced the deleteLater call by a new allocation.

    Why are you calling delete right after deleteLater ?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.