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;