Qt C++调用libssh2实现sftp传输文件,界面部分采用QML

news2024/7/2 21:14:52

文章目录

  • 1.重点说明
  • 2.测试环境搭建
  • 3.代码具体实现
      • 步骤1:安装libssh2
      • 步骤2:创建C++类处理SFTP文件传输
      • 步骤3:将C++类与QML绑定
      • 步骤4:创建QML界面
      • 步骤5:配置项目文件
      • 总结

1.重点说明

FTP、FTPS、SFTP不要混淆,我们这里是SFTP

1.1SFTP
SFTP(SSH File Transfer Protocol,也称 Secret File Transfer Protocol)是一种安全的文件传输协议,一种通过网络传输文件的安全方法;它确保使用私有和安全的数据流来安全地传输数据。
1.2 FTPS
FTPS是一种对常用的文件传输协议(FTP)添加传输层安全(TLS)和安全套接层(SSL)加密协议支持的扩展协议。FTPS不应与基于SSH的SSH文件传输协议或是Secure FTP协议相混淆。
1.3 FTP
FTP(File Transfer Protocol,文件传输协议) 是 TCP/IP 协议组中的协议之一。FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。其中FTP服务器用来存储文件,用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的资源。在开发网站的时候,通常利用FTP协议把网页或程序传到Web服务器上。此外,由于FTP传输效率非常高,在网络上传输大的文件时,一般也采用该协议。
默认情况下FTP协议使用TCP端口中的 20和21这两个端口,其中20用于传输数据,21用于传输控制信息。但是,是否使用20作为传输数据的端口与FTP使用的传输模式有关,如果采用主动模式,那么数据传输端口就是20;如果采用被动模式,则具体最终使用哪个端口要服务器端和客户端协商决定。

2.测试环境搭建

2.1 Xlight FTP工具
Xlight FTP服务器是非常容易使用的FTP服务器。 为了保证高性能,FTP服务器全部用C语言写成,服务器运行时占用很少的系统资源。它具有高效网络算法,在大量用户情况下, 可以充分利用FTP服务器带宽, 能够轻松处理数千用户的同时下载。

我们使用了Xlight FTP工具,具体安装和配置这里不提供!

3.代码具体实现

在Qt中使用C++调用libssh2实现SFTP文件传输,并使用QML实现一个简单的文件传输页面,需要几个关键步骤:

  1. 设置并配置libssh2库。
  2. 创建一个C++类处理SFTP文件传输。
  3. 将C++类与QML绑定。
  4. 创建QML界面来进行文件传输。

步骤1:安装libssh2

确保你已经安装了libssh2库。如果没有安装,可以使用以下命令进行安装:

  • Ubuntu/Debian:

    sudo apt-get install libssh2-1-dev
    
  • macOS:

    brew install libssh2
    

步骤2:创建C++类处理SFTP文件传输

创建一个C++类,用于处理与SFTP服务器的连接和文件传输。

sftpclient.h

#ifndef SFTPCLIENT_H
#define SFTPCLIENT_H

#include <QObject>
#include <libssh2.h>
#include <libssh2_sftp.h>
#include <QFile>

class SFTPClient : public QObject
{
    Q_OBJECT
public:
    explicit SFTPClient(QObject *parent = nullptr);
    ~SFTPClient();

    Q_INVOKABLE bool connectToServer(const QString &hostname, const QString &username, const QString &password, int port = 22);
    Q_INVOKABLE bool uploadFile(const QString &localFilePath, const QString &remoteFilePath);

signals:
    void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
    void uploadFinished(bool success);

private:
    LIBSSH2_SESSION *session;
    LIBSSH2_SFTP *sftpSession;
    int sock;

    bool initLibssh2();
    void cleanupLibssh2();
};

#endif // SFTPCLIENT_H

sftpclient.cpp

#include "sftpclient.h"
#include <QDebug>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>

SFTPClient::SFTPClient(QObject *parent) : QObject(parent), session(nullptr), sftpSession(nullptr), sock(-1)
{
    initLibssh2();
}

SFTPClient::~SFTPClient()
{
    cleanupLibssh2();
}

bool SFTPClient::initLibssh2()
{
    if (libssh2_init(0) != 0) {
        qDebug() << "libssh2 initialization failed";
        return false;
    }
    return true;
}

void SFTPClient::cleanupLibssh2()
{
    if (sftpSession) {
        libssh2_sftp_shutdown(sftpSession);
    }
    if (session) {
        libssh2_session_disconnect(session, "Normal Shutdown");
        libssh2_session_free(session);
    }
    if (sock != -1) {
        close(sock);
    }
    libssh2_exit();
}

bool SFTPClient::connectToServer(const QString &hostname, const QString &username, const QString &password, int port)
{
    struct sockaddr_in sin;
    struct hostent *host;
    
    // Resolve hostname
    host = gethostbyname(hostname.toStdString().c_str());
    if (!host) {
        qDebug() << "Failed to resolve hostname";
        return false;
    }

    // Create socket and connect
    sock = socket(AF_INET, SOCK_STREAM, 0);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    sin.sin_addr.s_addr = *(long *)(host->h_addr);

    if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
        qDebug() << "Failed to connect";
        return false;
    }

    // Create session
    session = libssh2_session_init();
    if (!session) {
        qDebug() << "Failed to create session";
        return false;
    }

    // Handshake
    if (libssh2_session_handshake(session, sock)) {
        qDebug() << "Failed to establish SSH session";
        return false;
    }

    // Authenticate
    if (libssh2_userauth_password(session, username.toStdString().c_str(), password.toStdString().c_str())) {
        qDebug() << "Authentication failed";
        return false;
    }

    // Initialize SFTP session
    sftpSession = libssh2_sftp_init(session);
    if (!sftpSession) {
        qDebug() << "Unable to initialize SFTP session";
        return false;
    }

    qDebug() << "Connected and authenticated";
    return true;
}

bool SFTPClient::uploadFile(const QString &localFilePath, const QString &remoteFilePath)
{
    if (!sftpSession) {
        qDebug() << "SFTP session not initialized";
        return false;
    }

    QFile localFile(localFilePath);
    if (!localFile.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to open local file";
        return false;
    }

    LIBSSH2_SFTP_HANDLE *sftpHandle = libssh2_sftp_open(sftpSession, remoteFilePath.toStdString().c_str(), LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC, LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR);
    if (!sftpHandle) {
        qDebug() << "Failed to open remote file";
        return false;
    }

    char buffer[1024];
    qint64 bytesRead;
    qint64 totalBytes = localFile.size();
    qint64 bytesSent = 0;

    while ((bytesRead = localFile.read(buffer, sizeof(buffer))) > 0) {
        char *ptr = buffer;
        while (bytesRead > 0) {
            int rc = libssh2_sftp_write(sftpHandle, ptr, bytesRead);
            if (rc < 0) {
                qDebug() << "Failed to write to remote file";
                libssh2_sftp_close(sftpHandle);
                return false;
            }
            ptr += rc;
            bytesRead -= rc;
            bytesSent += rc;
            emit uploadProgress(bytesSent, totalBytes);
        }
    }

    localFile.close();
    libssh2_sftp_close(sftpHandle);
    emit uploadFinished(true);
    return true;
}

步骤3:将C++类与QML绑定

main.cpp 中,将 SFTPClient 类注册到 QML 中。

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "sftpclient.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    SFTPClient sftpClient;

    engine.rootContext()->setContextProperty("sftpClient", &sftpClient);

    engine.load(QUrl(QStringLiteral("qrc:/Main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

步骤4:创建QML界面

创建一个简单的 QML 界面,允许用户输入服务器信息和文件路径,并进行文件传输。

Main.qml

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("SFTP Client")

    Column {
        anchors.centerIn: parent
        spacing: 20

        TextField {
            id: hostnameField
            width: parent.width - 40
            placeholderText: "Hostname"
        }

        TextField {
            id: usernameField
            width: parent.width - 40
            placeholderText: "Username"
        }

        TextField {
            id: passwordField
            width: parent.width - 40
            placeholderText: "Password"
            echoMode: TextInput.Password
        }

        TextField {
            id: localFileField
            width: parent.width - 40
            placeholderText: "Local File Path"
        }

        TextField {
            id: remoteFileField
            width: parent.width - 40
            placeholderText: "Remote File Path"
        }

        Button {
            text: "Connect and Upload"
            onClicked: {
                sftpClient.connectToServer(hostnameField.text, usernameField.text, passwordField.text)
                sftpClient.uploadFile(localFileField.text, remoteFileField.text)
            }
        }

        ProgressBar {
            id: progressBar
            width: parent.width - 40
            minimumValue: 0
            maximumValue: 100
        }

        Text {
            id: statusText
            text: ""
        }
    }

    Connections {
        target: sftpClient
        onUploadProgress: {
            progressBar.value = (bytesSent / bytesTotal) * 100
        }
        onUploadFinished: {
            statusText.text = success ? "Upload Finished" : "Upload Failed"
        }
    }
}

步骤5:配置项目文件

确保项目文件包含必要的模块和库链接。

project.pro

QT += qml quick gui network

CONFIG += c++11

SOURCES += main.cpp \
           sftpclient.cpp

HEADERS += sftpclient.h

RESOURCES += qml.qrc

# Add libssh2 library
LIBS += -lssh2

总结

以上代码实现了一个简单的Qt QML应用,可以连接S

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Advanced RAG 09:『提示词压缩』技术综述

编者按&#xff1a; 如何最大限度地发挥 LLMs 的强大能力&#xff0c;同时还能控制其推理成本&#xff1f;这是当前业界研究的一个热点课题。 针对这一问题&#xff0c;本期精心选取了一篇关于"提示词压缩"(Prompt Compression)技术的综述文章。正如作者所说&#xf…

VMware17.0 安装过程

VMware17.0 VMware 17.0 是一款功能强大的虚拟机软件&#xff0c;用于在计算机上创建和管理虚拟机。它能够同时运行多个操作系统&#xff0c;如 Windows、Linux 等&#xff0c;并且在这些虚拟机之间提供无缝的切换和共享功能。 VMware 17.0 支持最新的硬件和操作系统&#xf…

区间动态规划——最长回文子串(C++)

难得心静。 ——2024年6月30日 什么是区间动态规划&#xff1f; 区间动态规划通常以连续区间的求解作为子问题&#xff0c;例如区间 [i, j] 上的最优解用dp[i][j]表示。先在小区间上进行动态规划得到子问题的最优解&#xff0c;再利用小区间的最优解合并产生大区间的最优解。 …

ComfyUI高清放大的四种方式(工作流附件在最后)

方式一&#xff1a;Latent放大工作流 1.工作流截图 方式二&#xff1a;ESRGAN&#xff08;传统模型&#xff09;放大工作流 方式三&#xff1a;算法放大&#xff08;后期处理&#xff09;工作流 方式四&#xff1a;Ultimate SD Upscale工作流 这个方式的优势是对于显存底的用…

WP黑格导航主题BlackCandy

BlackCandy-V2.0全新升级&#xff01;首推专题区(推荐分类)更多自定义颜色&#xff01;选择自己喜欢的色系&#xff0c;焕然一新的UI设计&#xff0c;更加扁平和现代化&#xff01; WP黑格导航主题BlackCandy

代码随想录第37天|动态规划

01背包理论基础 参考 01背包: 每个物品只有一个, 只要选或不选两个选项 暴力解法: 回溯法枚举 dp[i][j]: i 表示 0 ~ i 的物品, j 表示容量, 数值表示当前的最大价值递推公式: max(dp[i-1][j], dp[i-1][j-weight[i]] value[i])初始化: j 0 时, 无法放任何有价值的物品, d…

目标检测常用涨点方法:注意力机制小结(空间注意力、通道注意力、CBAM等)

1.通道注意力 通道注意力&#xff08;Channel Attention&#xff09;是在通道维度上对输入数据进行学习&#xff0c;再对不同的通道分配相应的权重表示重要性&#xff0c;从而达到“分配注意力”的效果。SENet&#xff08;Squeeze and Excitation networks) 是一个典型的使用通…

MySQL高级-事务-并发事务演示及隔离级别

文章目录 0、四种隔离级别1、创建表 account2、修改当前会话隔离级别为 read uncommitted2.1、会出现脏读 3、修改当前会话隔离级别为 read committed3.1、可以解决脏读3.2、会出现不可重复读 4、修改当前会话隔离级别为 repeatable read&#xff08;默认&#xff09;4.1、解决…

C++(Python)肥皂泡沫普拉托边界膜曲面模型算法

&#x1f3af;要点 &#x1f3af;肥皂泡二维流体模拟 | &#x1f3af;泡沫普拉托边界膜曲面模型算法演化厚度变化 | &#x1f3af;螺旋曲面三周期最小结构生成 &#x1f4dc;皂膜用例&#xff1a;Python计算物理粒子及拉格朗日和哈密顿动力学 | Python和MATLAB粘性力接触力动…

ELK企业级实战

一、Elstic stack在企业的常⻅架构 https://www.bilibili.com/video/BV1x94y1674x/?buvidXY705117E90F73A790429C9CFBD5F70F22168&vd_source939ea718db29535a3847d861e5fe37ef ELK 解决取得问题 痛点1: ⽣产出现故障后&#xff0c;运维需要不停的查看各种不同的⽇志进⾏…

10款好用不火的PC软件,真的超好用!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/市场上有很多软件&#xff0c;除了那些常见的大众化软件&#xff0c;还有很多不为人知的小众软件&#xff0c;它们的作用非常强大&#xff0c;简洁…

骁龙相机拍照流程分析

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 1.deliverInputEvent 拍照点击事件处理 2.submitRequestList Camera 提交拍照请求 3.createCaptureRequest 拍照请求帧数 骁龙相机通过binder 数据传输…

小程序打包

一、manifest.json文件添加小程序id 二、接口校验&#xff0c;后端接口添加正式上线&#xff0c;有域名的地址 然后到微信公众平台-开发管理-服务器域名处配置request合法域名&#xff0c;在 此处能够看到后端的baseUrl 三、项目部署 四、发版 在小程序编辑器里 此处可以在…

微服务之服务保护策略【持续更新】

文章目录 线程隔离一、滑动窗口算法二、漏桶算法三、令牌桶算法 面试题1、Sentinel 限流和Gateway限流的区别 线程隔离 两种实现方式 线程池隔离&#xff08;Hystix隔离&#xff09;&#xff0c;每个被隔离的业务都要创建一个独立的线程池&#xff0c;线程过多会带来额外的CPU…

Android跨进程通信,binder传输数据过大导致客户端APP,Crash,异常捕获,监听异常的数值临界值,提前Hook拦截。

文章目录 Android跨进程通信&#xff0c;binder传输数据过大导致Crash&#xff0c;异常捕获&#xff0c;监听异常的数值临界值&#xff0c;提前Hook拦截。1.binder在做跨进程传输时&#xff0c;最大可以携带多少数据1.1有时候这个1m的崩溃系统捕获不到异常&#xff0c; 2.监测异…

大模型系列课程学习-基于2080TI-22G魔改卡搭建双卡大模型训练平台(双系统)

1.选择合适的硬件配置 再配置电脑之前&#xff0c;需要确认自己需要的显存大小、主板、内存条、电源、散热等核心配件。经过前期调研&#xff0c;选择的硬件配置如下&#xff1a; &#xff08;1&#xff09;主板&#xff1a;华南X99_F8D(DDR4主板)&#xff0c;因为需要支持双卡…

springboot 3.x相比之前版本有什么区别

Spring Boot 3.x相比之前的版本&#xff08;尤其是Spring Boot 2.x&#xff09;&#xff0c;主要存在以下几个显著的区别和新特性&#xff1a; Java版本要求&#xff1a; Spring Boot 3.x要求至少使用Java 17作为最低版本&#xff0c;同时已经通过了Java 19的测试&#xff0c;…

【C语言】指针剖析(完结)

©作者:末央&#xff06; ©系列:C语言初阶(适合小白入门) ©说明:以凡人之笔墨&#xff0c;书写未来之大梦 目录 回调函数概念回调函数的使用 - qsort函数 sizeof/strlen深度理解概念手脑并用1.sizeof-数组/指针专题2.strlen-数组/指针专题 指针面试题专题 回调函…

C++ | Leetcode C++题解之第205题同构字符串

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isIsomorphic(string s, string t) {unordered_map<char, char> s2t;unordered_map<char, char> t2s;int len s.length();for (int i 0; i < len; i) {char x s[i], y t[i];if ((s2t.coun…

HDFS详细介绍以及HDFS集群环境部署【hadoop组件HDFS笔记】(图片均为学习时截取的)

HDFS详细介绍 HDFS是什么 HDFS是Hadoop三大组件(HDFS、MapReduce、YARN)之一 全称是&#xff1a;Hadoop Distributed File System&#xff08;Hadoop分布式文件系统&#xff09;&#xff1b;是Hadoop技术栈内提供的分布式数据存储解决方案 可以在多台服务器上构建存储集群&…