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
乾貨來了,這裏說這下我對這兩種情況的處理方法:
- 對於需要同步處理的情況
同步情況我選擇在ftpCommandFinished
槽函數中等待返回值的情況,在等待的同時又一個時間範圍,考慮到某些操作的耗時性,我這裏統一設置等待時間爲1分鐘,如果超過一分鐘默認爲該操作執行失敗,等待情況下需要QApplication::processEvents();
能保證執行到槽函數裏面 - 對於斷網後需要重新
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;