Qt+QSSH实现SFTP
1.下载qssh源码
github链接
https://github.com/mardy/QSsh/tree/botan-1
Gitee链接
https://gitee.com/shikai1995/qssh-botan-1/tree/botan-1/
需要使用botan分支
2.编译
使用QtC打开qssh.pro,编译src项目
3.获取相关库
lib文件夹里有lib和dll,分别时botan和qssh的;src/libs/ssh里有头文件(可以把h文件以外的都删除);
拿出来分别放在lib文件夹和include文件夹里,dll放在可执行程序路径
4.使用,pro
# qssh库使用 win32 { CONFIG(debug, debug|release) { LIBS += -L$$PWD/qssh/lib/ -lQSshd LIBS += -L$$PWD/qssh/lib/ -lBotand } else { LIBS += -L$$PWD/qssh/lib/ -lQSsh LIBS += -L$$PWD/qssh/lib/ -lBotan } } INCLUDEPATH += $$PWD/qssh/include
5.头文件封装
#ifndef FTPCLIENT_H #define FTPCLIENT_H #include <QObject> #include "BaseComm.h" #include <QUrl> #include <QNetworkAccessManager> #include <QNetworkReply> #include <QNetworkRequest> #include <QFile> #include <QFileInfo> #include <QEvent> #include "sshconnection.h" #include "sftpchannel.h" class FtpClient : public BaseComm { Q_OBJECT public: explicit FtpClient(CommPlugin* commPlugin, QObject* parent = nullptr); ~FtpClient(); struct TransforJob { QString localFilePath = ""; QString remoteFilePath = ""; bool isUploadFile = true; SFtpServerConfig sFtpServerConfig; }; void appendTrasforFileJob(const QString& localFilePath, //创建传输文件的任务 const QString& remoteFilePath, const SFtpServerConfig& cfg, bool isUploadFile); signals: void transforFileSig(); private slots: void on_init(); void on_onnected(); //连接服务器成功 void on_transforFileSig(); private: void loopTrasforFile(); //线程函数,循环获取文件传输任务列表里的任务并执行 void trasforFile(const TransforJob& job); private: QSharedPointer<QSsh::SftpChannel> m_sftpChannel = nullptr; //sftp传输通道 std::shared_ptr<QSsh::SshConnection> m_sshConnection = nullptr; //sftp连接对象 std::queue<TransforJob> m_transforJobs; TransforJob m_curTransforJob;//当前正在传输的job std::mutex m_transforJobMutex; std::condition_variable m_transforJobCdt; std::atomic_bool m_isTransforing = { false }; //正在传输文件标志位 std::atomic_bool m_working = { true }; //获取文件传输任务线程运行标志位 }; #endif // FTPCLIENT_H
6.cpp文件封装
#include "FtpClient.h" #include <QJsonDocument> #include <QJsonObject> #include <QTimer> #include <QThread> FtpClient::FtpClient(CommPlugin* commPlugin, QObject* parent) : BaseComm{ commPlugin, parent } { } FtpClient::~FtpClient() { m_working = false; } void FtpClient::on_init() { //[1] 创建线程循环从任务列表获取任务并执行 std::thread threadTrasforFile(&FtpClient::loopTrasforFile, this); threadTrasforFile.detach(); //[2] 订阅消息 QObject::connect(this, &FtpClient::transforFileSig, this, &FtpClient::on_transforFileSig); } void FtpClient::appendTrasforFileJob(const QString &localFilePath, const QString &remoteFilePath, const SFtpServerConfig &cfg, bool isUploadFile) { //[1] 创建传输任务 TransforJob transforJob; transforJob.isUploadFile = isUploadFile; transforJob.localFilePath = localFilePath; transforJob.remoteFilePath = remoteFilePath; transforJob.sFtpServerConfig = cfg; //[2] 将任务放到任务队列中 std::unique_lock<std::mutex> locker(m_transforJobMutex); m_transforJobs.push(transforJob); locker.unlock(); //[3] 如果当前没有传输任务则告诉传输线程可以传输 if(!m_isTransforing) { m_transforJobCdt.notify_one(); } } void FtpClient::loopTrasforFile() { while(m_working) //只要程序没有关就一直从任务池里获取任务并执行 { std::unique_lock<std::mutex> locker(m_transforJobMutex); //[1] 判断是否有任务 while(m_transforJobs.empty()) { m_transforJobCdt.wait(locker); } //[2] 如果有正在执行的任务则退回 if(m_isTransforing) { QThread::msleep(100); continue; } //[3] 获取队列中的首个任务 m_curTransforJob = m_transforJobs.front(); m_transforJobs.pop(); locker.unlock(); //[4] 将标志位置为true并开始执行任务 m_isTransforing = true; emit transforFileSig(); } } void FtpClient::on_transforFileSig() { //[1] 创建连接 QSsh::SshConnectionParameters argParameters; argParameters.setHost(QString::fromStdString(m_curTransforJob.sFtpServerConfig.host)); argParameters.setPort(m_curTransforJob.sFtpServerConfig.port); argParameters.setUserName(QString::fromStdString(m_curTransforJob.sFtpServerConfig.userName)); argParameters.setPassword(QString::fromStdString(m_curTransforJob.sFtpServerConfig.passWord)); argParameters.timeout = 10; argParameters.authenticationType = QSsh::SshConnectionParameters::AuthenticationTypePassword; //密码方式连接 //[2] 状态判断 if (m_sshConnection) { m_sshConnection.get()->disconnect(); m_sshConnection.reset(); m_sshConnection = nullptr; } //[3] 连接初始化 m_sshConnection = std::make_shared<QSsh::SshConnection>(argParameters); //[4] 连接成功执行的槽函数 QObject::connect(m_sshConnection.get(), &QSsh::SshConnection::connected, this, &FtpClient::on_onnected, Qt::DirectConnection); //[4] 连接失败执行的槽函数 QObject::connect(m_sshConnection.get(), &QSsh::SshConnection::error, this, [this](QSsh::SshError err){ LOG_ERR(QString("sftp连接异常:%1").arg(err).toStdString()); //dosomething m_isTransforing = false; }, Qt::DirectConnection); //[5] 开始连接服务器 m_sshConnection->connectToHost(); } void FtpClient::on_onnected() { do { //[1] 连接服务器成功,发送界面提示 LOG_INFO(QString("连接sftp服务器成功").toStdString()); { //dosomething } //[2] 创建ftp通道 if(m_sftpChannel) { m_sftpChannel.data()->disconnect(); m_sftpChannel.clear(); m_sftpChannel = nullptr; } m_sftpChannel = m_sshConnection->createSftpChannel(); if (!m_sftpChannel) { LOG_ERR("sftpChannel create failed."); m_isTransforing = false; return; } //[3] chanel初始化成功执行的槽函数 QObject::connect(m_sftpChannel.data(), &QSsh::SftpChannel::initialized, this, [this]() { LOG_INFO(QString("sftp chanel初始化成功").toStdString()); //dosomethingif(m_curTransforJob.isUploadFile) { m_sftpChannel->uploadFile(m_curTransforJob.localFilePath, m_curTransforJob.remoteFilePath, QSsh::SftpOverwriteExisting); } else { m_sftpChannel->downloadFile(m_curTransforJob.remoteFilePath, m_curTransforJob.localFilePath, QSsh::SftpOverwriteExisting); } }, Qt::DirectConnection); //[4] chanel有异常执行的槽函数 QObject::connect(m_sftpChannel.data(), &QSsh::SftpChannel::channelError, this, [this](const QString& reason) { LOG_ERR(QString("sftp chanel error:%1").arg(reason).toStdString()); //dosomething m_isTransforing = false; }, Qt::DirectConnection); //[5] 文件传输完成执行的槽函数 QObject::connect(m_sftpChannel.data(), &QSsh::SftpChannel::finished, this, [this](QSsh::SftpJobId id, QString error) { QString transforFilePath; int state = 1; if (m_curTransforJob.isUploadFile) { transforFilePath = m_curTransforJob.localFilePath; state = 1; } else { transforFilePath = m_curTransforJob.remoteFilePath; state = 2; } //dosomething LOG_INFO(QString("文件传输完成:%1").arg(transforFilePath).toStdString()); //传输完成回收当次连接和通道 m_sftpChannel->closeChannel(); m_sftpChannel.reset(); m_sftpChannel = nullptr; m_sshConnection.get()->disconnect(); m_sshConnection.reset(); m_sshConnection = nullptr; //重置标志位以进行下次传输 m_isTransforing = false; }, Qt::DirectConnection); //[6] 初始化channel m_sftpChannel->initialize(); } while (0); }
长风破浪会有时,直挂云帆济沧海!
可通过下方链接找到博主
https://www.cnblogs.com/judes/p/10875138.html