QFtp在QT5版本下使用时遇到部分问题解决方案

QFtp

       QFtp在QT5版本之后就被QNetworkAccessManager代替,但是QNetworkAccessManager仅支持ftp的上传put和下载get,对于没有需要ftp以下功能的还是建议使用QNetworkAccessManager,主要包括:list()、cd()、remove()、mkdir()、rename()、rawCommand()

       QFtp的所有命令都会返回一个唯一标识符,允许跟踪当前正在执行的命令。当命令开始执行时,发出commandStarted()信号;当命令完成时发送commandFinished()信号,并带有命令标识符和bool类型参数,以便表示该命令有没有执行成功。但是在线程情况下,断网重连后会出现其他问题。需要特殊处理。

       QFtp工作机制是异步的,所以没有阻塞函数,如果需要同步的、序列的执行某些操作就需要自己实现同步阻塞。还有一种情况,在网络正常的情况下保证同步执行就没有问题了,网络不正常的情况下还会出现另一种情况,整个QFtp的socket停止工作了,并且会清空list执行列表

QFtp 不包含示例源码下载:QFtp无示例源码下载

QFtp 含示例源码下载:

GitHub 网址下载 https://github.com/qt/qtftp
命令下载 git clone https://github.com/qt/qtftp

       本博客旨在讲,QFtp在线程情况下出现断网以及需要同步等待的情况下的个人处理方案:

常规QFtp使用方式:

new QFtp
// 绑定信号槽
// 实现槽函数
ftp->connectToHost(**IP**, **POST**); // 连接服务器
ftp->login(**用户名**, **密码**); 	// 登录服务器

// cd 、list 访问 、mkdir 
// put 
// close等

       但是Qt5以后官方已经将QFtp丢弃,使用QNetworkAccessManager了,即使自己重新编译后,使用时也会遇到bug,比如在想要同步使用时,比如在断网的情况下都会有问题,断网或者操作失败情况下的问题尤为明显,如果一旦失败,那么QFtp会将下面所有的待执行步骤都清空,这个时候再次重新将那些不走都不行,需要重新new才能再次使用QFtp

       干货来了,这里说这下我对这两种情况的处理方法:

  1. 对于需要同步处理的情况
    同步情况我选择在ftpCommandFinished槽函数中等待返回值的情况,在等待的同时又一个时间范围,考虑到某些操作的耗时性,我这里统一设置等待时间为1分钟,如果超过一分钟默认为该操作执行失败,等待情况下需要QApplication::processEvents();能保证执行到槽函数里面
  2. 对于断网后需要重新new重新连的情况
    断网或者失败情况下,我这里按照上面说的方法直接设置为重新new后进行连接

下面代码中解释一下我这两种情况的处理方法其他也类似于此(以连接和登录为例):

// 连接
ftp->connectToHost(Ftp_Ip, Ftp_Port);
g_iTotal = 0;			
while(!b_connect_finished)  			// while循环用来等待执行完成或者判断执行失败
{
	++g_iTotal;
    QApplication::processEvents();		// 用来保证槽函数可以执行到槽函数
    msleep(100);

    if(g_iTotal >= 60)
    {
        resetFtp();						// 用来重置QFtp保证下次可以重新访问,执行操作
        g_iTotal = 0;
        qDebug() << "resetFtp" << b_connect_finished;
        return ;
    }
};
b_connect_finished = false;				// 成功后重置

// 登录
ftp->login(Ftp_User, Ftp_PassWord);
g_iTotal = 0;
while(!b_login_finished)
{
    ++g_iTotal;
    QApplication::processEvents();
    msleep(100);

    if(g_iTotal >= 60)
    {
        resetFtp();
        g_iTotal = 0;
        qDebug() << "resetFtp" << b_login_finished;
        return;
    }
};
b_login_finished = false;
	// resetFtp函数中的内容
	
	// 第一次连接不执行该操作,主要用来清楚上次一次的连接,防止是真卡了或者还有正在执行的操作
	if(!b_FirstOK)
    {
        ftp->state();
        ftp->abort();
        ftp->deleteLater();
        ftp = nullptr;
    }
    ftp = new QFtp();

	// 槽函数部分采用 lambda 表达式的方式,主要是为了解决在线程中不响应的问题
    connect(ftp, &QFtp::commandStarted, [](int state)
    {
        Q_UNUSED(state);

        if(ftp->currentCommand() == QFtp::ConnectToHost){
            qDebug()<<"正在连接到服务器…";
        }
        if (ftp->currentCommand() == QFtp::Login){
            qDebug()<<"正在登录…";
        }
        if (ftp->currentCommand() == QFtp::Get){
           qDebug()<<"正在下载…";
        }
        if (ftp->currentCommand() == QFtp::Put){
            qDebug()<<"正在上传…";
        }
        else if (ftp->currentCommand() == QFtp::Close){
            qDebug()<<"正在关闭连接…";
        }
    });

    connect(ftp, &QFtp::dataTransferProgress, [this](qint64 readBytes,qint64 totalBytes)
    {
        emit uploadprogress(readBytes,totalBytes);
    });

    connect(ftp,&QFtp::commandFinished, [](int id, bool error)
    {
        Q_UNUSED(id);

        if(ftp->currentCommand() == QFtp::ConnectToHost)
        {
            if(error)
            {
                qDebug()<<tr("连接服务器出现错误:%1").arg(ftp->errorString());
            }
            else
            {
               qDebug()<<"连接到服务器成功";
               b_connect = true;
            }
            b_connect_finished = true;
        }
        else if(ftp->currentCommand() == QFtp::Login)
        {
            if(error)
            {
                qDebug()<<tr("登录出现错误:%1").arg(ftp->errorString());
            }
            else
            {
                qDebug()<<"connect successful";
                b_login = true;
            }
            b_login_finished = true;
        }
        else if(ftp->currentCommand() == QFtp::Put)
        {
            if(error)
            {
                qDebug()<<tr("上传出现错误:%1").arg(ftp->errorString());
            }
            else
            {
                qDebug()<<tr("上传完成");
                b_upload = true;
            }
            b_upload_finished = true;
        }
        //处理list命令完成时的情况:
        else if(ftp->currentCommand() == QFtp::List)
        {
            if(error)
            {
                qDebug()<<tr("List command fail");
            }
            else
            {
                qDebug()<<tr("List command success");
                b_list = true;
            }
            b_list_finished = true;
        }
        else if(ftp->currentCommand() == QFtp::Close)
        {
            if(error)
            {
                qDebug()<<tr("关闭连接失败");
            }
            else
            {
                qDebug()<<tr("已经关闭连接");
                b_disconnect = true;
            }
            b_disconnect_finished = true;
        }
        else if(ftp->currentCommand() == QFtp::Mkdir)
        {
            if(error)
            {
                qDebug()<<tr("目录创建完成失败");
            }
            else
            {
                qDebug()<<tr("目录创建完成");
                b_creatdir = true;
            }
            b_creatdir_finished = true;
        }
        else if(ftp->currentCommand() == QFtp::Remove)
        {
            if(error)
            {
                qDebug()<<tr("List command fail");
            }
            else
            {
                qDebug()<<tr("List command success");
                b_remove = true;
            }
            b_remove_finished = true;
        }
        else if(ftp->currentCommand() == QFtp::Cd)
        {
            if(error)
            {
                qDebug()<<tr("目录跳转失败");
            }
            else
            {
                qDebug()<<tr("目录跳转");
                b_setdir = true;
            }
            b_setdir_finished = true;
        }
    });

    connect(ftp,&QFtp::stateChanged, [](int state)
    {
        if(state == QFtp::Unconnected)
        {
            qDebug()<<"未连接到主机";
        }
        if(state == QFtp::Connected)
        {
            qDebug()<<"已经连接到主机";
        }
        if(state == QFtp::HostLookup)
        {
            qDebug()<<"正在查找主机";
        }
        if(state == QFtp::LoggedIn)
        {
            qDebug()<<"已经登录";
        }
        if(state == QFtp::Closing)
        {
            qDebug()<<"连接正在关闭";
        }
    });

    connect(ftp, &QFtp::listInfo, [](QUrlInfo urlInfo)
    {
        qDebug() << urlInfo.name();
        Ldf.str_filename = urlInfo.name();
        ListDirFiles.push_back(Ldf);
    });
    b_FirstOK = false;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章