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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章