Qt+QSSH实现SFTP

news/2025/3/31 11:33:51/文章来源:https://www.cnblogs.com/judes/p/18797522

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);}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/907028.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

行政管理系统推荐几个比较好的?

之前写过一篇关于行政管理资料的,指路>> HR猫姐:公司行政究竟是干什么的?这份1000+行政资料收好! 这篇就分享一个我们团队现在正在用的行政管理系统吧——戳此自取模板>> 简道云行政管理系统下面来详细介绍下我们现在主要在用的几个功能: 01 应付/应收合同管理…

【Java】【XXL-job】自己的项目调度任务中心

之前,我们已经学习了xxl-job的入门:https://www.cnblogs.com/luyj00436/p/18780550 。这里的任务执行,调用的是demo。 那么我们自己的项目,如果使用xxl-job?自己的项目,相当于执行器,只要把自己的项目,仿造xxl-job-executor-sample-springboot,即可。 步骤新建Springb…

【Vue】自定义滚动条

<!-- 滚动条开始 --><div class="custom-scrollbar-container"><!-- 添加左右箭头按钮 --><div class="scroll-arrow left-arrow" @click="scrollBy(-100)"><i class="iconfont"style="transform: ro…

重庆软航NTKO WebOffice控件在谷歌Chrome 133版提示扩展已停用解决方案!

NTKO WebOffice‌是重庆软航公司的一款能够在浏览器中直接编辑Microsoft Office、WPS、金山电子表等文档的控件,支持Word、Excel等多种文档格式。该控件能够在IE、Chrome等浏览器中运行,并支持强制痕迹保留、禁止拷贝、模版套红、全文批注等功能‌。 但是软航NTKO WebOffice‌…

5个关键步骤优化IPD流程实施效果

IPD(Integrated Product Development)流程即集成产品开发流程,是一套产品开发的模式、理念与方法。它强调将产品开发视为一个完整的流程,涵盖从市场需求分析、产品规划、设计开发到生产制造、上市销售等各个环节,旨在通过跨部门的团队协作,高效、高质量地推出满足市场需求…

VirtualBox安装Ubuntu教程

下载 VirtualBox官方下载非老旧电脑还是推荐VMware,性能好一些,现在也免费了。官网下载 官网下载慢的话,可以使用我下载好的 Ubuntu清华镜像下载根据自己电脑类型选择下载! 安装完成后 创建 控制 -> 新建等待...... 登录

PLM软件实施最佳实践:企业如何高效落地?

PLM(Product Lifecycle Management)软件,即产品生命周期管理软件,旨在助力企业对产品从概念设计到退役处理的全生命周期进行有效管理。通过整合产品数据、流程以及人员,PLM软件能显著提升企业的创新能力、生产效率并降低成本。然而,PLM软件的实施并非易事,众多企业在落地…

HTTP500代码怎么解决?常见的5xx网页错误及其原因

要修复5xxx错误,您需要解决服务器上导致该错误的问题,这可能需要代码调试、配置更新或安装新的系统组件,接下来为大家带来HTTP 500错误的解决方法,和常见的5xx网页错误及其原因。错误 500 是什么? HTTP 500 响应代码并不表示实际问题,它只是通知您服务器出现了问题。 内部…

Vue 插槽 slot-scope=scope

============================================================== 默认插槽 只有一个slot 具名插槽 当有多个slot时,每个slot有名字的插槽(name) 只有template才能用v-slot 【这个是新设计的技术 Vue2.6以后用的】作用域插槽 反向传数据 App.vue中,必须用 template 数…

VMware Workstation不支持的硬件版本,模块Upgrade启动失败

1、我是从高版本的VMware Workstation降级后,再打开之前的虚拟机报错如下 2、打开虚拟机文件目录,用文本打开虚拟机的 .vmx文件,搜索定位到 virtualHW 字段,修改该字段为自己当前VMware版本,然后保存并开机

Next.js中间件权限绕过漏洞分析(CVE-2025-29927)

本文代码版本为next.js-15.2.2 本篇文章首发在先知社区:https://xz.aliyun.com/news/17403 一、漏洞概述 CVE-2025-29927是Next.js框架中存在的一个高危中间件逻辑绕过漏洞,允许攻击者通过构造特定HTTP请求头,绕过中间件的安全控制逻辑(如身份验证、路径重写、CSP防护等)。…