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/ -lQSshdLIBS += -L$$PWD/qssh/lib/ -lBotand } else {LIBS += -L$$PWD/qssh/lib/ -lQSshLIBS += -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());QJsonObject jsonObject;jsonObject.insert("state", 2);jsonObject.insert("info", QString("sftp连接异常:%1").arg(err));QJsonDocument jsonDoc(jsonObject);this->submitMsg(TopicSFTPState, jsonDoc.toJson().toStdString());m_isTransforing = false;}, Qt::DirectConnection);//[5] 开始连接服务器m_sshConnection->connectToHost(); }void FtpClient::on_onnected() {do {//[1] 连接服务器成功,发送界面提示LOG_INFO(QString("连接sftp服务器成功").toStdString());{QJsonObject jsonObject;jsonObject.insert("state", 1);jsonObject.insert("info", QString("连接sftp服务器成功"));QJsonDocument jsonDoc(jsonObject); //将JSON对象转换为QJsonDocumentthis->submitMsg(TopicSFTPState, jsonDoc.toJson().toStdString());}//[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());QJsonObject jsonObject;jsonObject.insert("state", 3);jsonObject.insert("info", "创建sftp通道成功");QJsonDocument jsonDoc(jsonObject);this->submitMsg(TopicSFTPState, jsonDoc.toJson().toStdString());if(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());QJsonObject jsonObject;jsonObject.insert("state", 4);jsonObject.insert("info", QString("sftp通道异常:%1").arg(reason));QJsonDocument jsonDoc(jsonObject);this->submitMsg(TopicSFTPState, jsonDoc.toJson().toStdString());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;}QJsonObject jsonObject;jsonObject.insert("jobId", QJsonValue::fromVariant(id));jsonObject.insert("state", state);jsonObject.insert("filePath", transforFilePath);jsonObject.insert("info", QString("文件传输完成:%1").arg(transforFilePath));QJsonDocument jsonDoc(jsonObject);this->submitMsg(TopicSFTPTransferState, jsonDoc.toJson().toStdString());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] 初始化channelm_sftpChannel->initialize();} while (0);}