SSH连接SFTP传输:如何使用libssh库在windows环境下进行(文件、文件夹)传输到远端服务器

news2024/11/29 3:03:31

  • 配置环境
  • cmake编译libssh
  • 如何使用生成的dll与lib文件
    • 配置lib 方法一
    • 配置lib 方法二
    • 配置dll方法一 将dll配置进入环境变量
    • 配置dll方法二 在编译过后将dll直接与可执行文件.exe文件放在同一目录下
    • 传输文件、文件夹代码(适配windows)

由于windows上的编译器一般都是没有libssh库的,所以如何我们想要使用libssh库那么我们将会使用cmake来编译libssh官网给出的源代码

libssh库下载地址:https://www.libssh.org/files/

在这里插入图片描述

配置环境

我们在编译libssh库之前需要先配置一些环境:

  • a) 安装 Visual Studio 或者 MinGW
  • b) 安装OpenSSL http://slproweb.com/products/Win32OpenSSL.htmlC:\Program Files
  • c) 安装zlib http://zlib.net/zlib128-dll.zipC:\Program Files
  • d) 安装CMake http://cmake.org/cmake/resources/software.html

有些库需要将其.dll加入环境变量,具体可自行探索

cmake编译libssh

解压压缩包,进入目录,在当前页面右键打开终端
在这里插入图片描述
执行以下命令:

mkdir build
cd build
cmake ..

如果出现一些报错很可能是配置环境的问题,可以观察报错信息逐一解决

打开libssh.sln项目(使用cmake编译的编译器与打开的编译器需一致)
在这里插入图片描述
ssh设为启动项目
在这里插入图片描述
Ctrl + B生成解决项目,生成dlllib文件
在这里插入图片描述

如何使用生成的dll与lib文件

配置lib 方法一

打开vs工程 -》 项目 -》 属性

  1. 将头文件也就是进入include下的路径添加进入附加包含目录
    G:\xxx\libssh-0.10.0\include
    在这里插入图片描述
  2. .lib文件所在目录添加进入附加库目录
    G:\xxx\libssh-0.10.0\build\src\Debug
    在这里插入图片描述
  3. ssh.lib添加进入附加依赖项
    在这里插入图片描述

配置lib 方法二

ssh.lib文件复制到当前项目所在路径下
在这里插入图片描述

ssh.lib导入项目即可,同理头文件也可直接复制进入项目路径
在这里插入图片描述

  • 如果是第一种方法,头文件引入可以#include <libssh/libssh.h> #include <libssh/sftp.h>
  • 如果是第二种方法,头文件引入必须#include "libssh/libssh.h" #include "libssh/sftp.h"

如果编译报错缺少这个文件libssh_version.h
这个文件在这个路径下G:\xxx\libssh-0.10.0\build\include\libssh,可以直接复制到libssh/下使用
在这里插入图片描述

配置dll方法一 将dll配置进入环境变量

点击此电脑 -》右键属性 -》 点击高级系统设置
在这里插入图片描述
在这里插入图片描述
dll文件所在路径添加进入环境变量
G:\xxx\libssh-0.10.0\build\src\Debug
在这里插入图片描述
在这里插入图片描述

配置dll方法二 在编译过后将dll直接与可执行文件.exe文件放在同一目录下

要使得用libssh库的项目能通过编译,需要将头文件以及.lib配置进入项目

如果出现__imp__ xxx类型的链接错误很有很可能是当前项目是X86环境,而libssh库是X64的库,需要将vs执行环境改为X64

传输文件、文件夹代码(适配windows)

int sftp_normal_upload(ssh_session session, sftp_session sftp, const char* local_file_path, const char* remote_file_path)
{
    sftp_file file = sftp_open(sftp, remote_file_path, O_WRONLY | O_CREAT, 0666);
    if (!file) {
        fprintf(stderr, "Failed to open remote file: %s:sftp_get_error(%d)\n", remote_file_path, sftp_get_error(sftp));
        fprintf(stderr, "Can't create directory: %s\n", ssh_get_error(session));
        return -1;
    }

    FILE* local_file = fopen(local_file_path, "rb");
    if (!local_file) {
        fprintf(stderr, "Failed to open local file: %s\n", local_file_path);
        sftp_close(file);
        return -1;
    }

    // 上传文件内容
    char buffer[1024];
    size_t bytes_read;
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), local_file)) > 0) {
        sftp_write(file, buffer, bytes_read);
    }

    fclose(local_file);
    sftp_close(file);
    return 1;
}



int sftp_recursive_upload(ssh_session session, sftp_session sftp, const char* local_path, const char* remote_path) {

    // 计算转换后的宽字符所需缓冲区大小
    int bufferSize_local = MultiByteToWideChar(CP_ACP, 0, local_path, -1, NULL, 0);
    int bufferSize_remote = MultiByteToWideChar(CP_ACP, 0, remote_path, -1, NULL, 0);

    // 分配缓冲区
    wchar_t* local_path_to_wchar = (wchar_t*)malloc(bufferSize_local * sizeof(wchar_t));
    wchar_t* remote_path_to_wchar = (wchar_t*)malloc(bufferSize_remote * sizeof(wchar_t));
    if (local_path_to_wchar == NULL || local_path_to_wchar == NULL) {
        fprintf(stderr, "Failed to memory\n");
        // 处理内存分配失败的情况
        return -1;
    }

    // 执行转换
    MultiByteToWideChar(CP_ACP, 0, local_path, -1, local_path_to_wchar, bufferSize_local);
    MultiByteToWideChar(CP_ACP, 0, remote_path, -1, remote_path_to_wchar, bufferSize_remote);

    //给local_path追加通配符
    const wchar_t* str = L"\\*";
    wchar_t local_current[MAX_PATH];

    if (wcslen(local_path_to_wchar) + 3 >= MAX_PATH - 1)
    {
        fprintf(stderr, "Failed to strcat wildcard character\n");
        return -1;
    }
    // 将str1复制到result中
    wcscpy(local_current, local_path_to_wchar);
    // 追加str2到result中
    wcscat(local_current, str);


    // 打开本地目录
    WIN32_FIND_DATA FindFileData;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    hFind = FindFirstFile(local_current, &FindFileData);
    if (hFind == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "Failed to open local directory: %s\n", local_current);
        return -1;
    }

    // 创建服务器目录
    sftp_mkdir(sftp, remote_path, 0777);

    // 遍历本地目录项
    do {
        if (wcscmp(FindFileData.cFileName, L".") != 0 && wcscmp(FindFileData.cFileName, L"..") != 0) {
            // 构造全路径
            wchar_t local_file_path[MAX_PATH];
            _snwprintf(local_file_path, sizeof(local_file_path), L"%s\\%s", local_path_to_wchar, FindFileData.cFileName);
            wchar_t remote_file_path[MAX_PATH];
            _snwprintf(remote_file_path, sizeof(remote_file_path), L"%s/%s", remote_path_to_wchar, FindFileData.cFileName);

            // 将宽字符字符串转换为多字节字符字符串
            char local_next[MAX_PATH];
            char remote_next[MAX_PATH];
            if (wcstombs(local_next, local_file_path, sizeof(local_next)) == (size_t)-1 ||
                wcstombs(remote_next, remote_file_path, sizeof(remote_next)) == (size_t)-1) {
                fprintf(stderr, "wchar_t conversion to char failed\n");
                return -1;
            }

            // 如果本地条目是一个目录,递归上传它
            if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                sftp_recursive_upload(session, sftp, local_next, remote_next);
            }
            else { // 如果本地条目是一个普通文件,上传它
                sftp_normal_upload(session, sftp, local_next, remote_next);
            }
        }
    } while (FindNextFile(hFind, &FindFileData) != 0);

    free(local_path_to_wchar);
    free(remote_path_to_wchar);
    FindClose(hFind);
    return 1;
}


ssh_session ssh_create(const char* target_host, const char* target_username)
{
    ssh_session session;

    // 连接SSH会话
    session = ssh_new();
    if (!session) {
        fprintf(stderr, "Failed to create SSH session\n");
        return NULL;
    }

    ssh_options_set(session, SSH_OPTIONS_HOST, target_host);
    ssh_options_set(session, SSH_OPTIONS_USER, target_username);

    if (ssh_connect(session) != SSH_OK) {
        fprintf(stderr, "Failed to connect to SSH session: %s\n", ssh_get_error(session));
        ssh_free(session);
        return NULL;
    }
    return session;
}

int sftp_run(ssh_session session, const char* local_file_dir, const char* target_path)
{
    sftp_session sftp;

    // 打开SFTP通道
    sftp = sftp_new(session);
    if (!sftp) {
        fprintf(stderr, "Failed to create SFTP session\n");
        ssh_disconnect(session);
        ssh_free(session);
        return -1;
    }

    if (sftp_init(sftp) != SSH_OK) {
        fprintf(stderr, "Failed to initialize SFTP session\n");
        sftp_free(sftp);
        ssh_disconnect(session);
        ssh_free(session);
        return -1;
    }


    // 得到当前 文件/目录 所在路径
    char local_dir[4096];
    getcwd(local_dir, sizeof(local_dir));
    int len = strlen(local_dir);
    if ((len + strlen(local_file_dir) + 2) >= 4095) {
        perror("Local filename is too long");
        return -1;
    }

    local_dir[len] = '\\';
    local_dir[len + 1] = '\0';
    strcat(local_dir, local_file_dir);

    struct _stat file_stat;

    // 获取文件的详细信息
    if (_stat(local_dir, &file_stat) != 0) {
        perror("stat");
        return -1;
    }

    // 判断文件类型

    //普通文件
    if ((file_stat.st_mode & _S_IFMT) == _S_IFREG) {
        sftp_normal_upload(session, sftp, local_dir, target_path);
    }
    //目录文件
    else if ((file_stat.st_mode & _S_IFMT) == _S_IFDIR) {
        // 递归上传本地目录到远程目录
        if (sftp_recursive_upload(session, sftp, local_dir, target_path) != 1) {
            fprintf(stderr, "Failed to recursively upload directory\n");
            sftp_free(sftp);
            ssh_disconnect(session);
            ssh_free(session);
            return -1;
        }
    }
    else {
        printf("%s 既不是普通文件,也不是目录,无法上传\n", local_dir);
    }

    // 释放
    sftp_free(sftp);
    ssh_disconnect(session);
    ssh_free(session);

    return 1;
}

int ssh_sftp_transmit_password(const char* target_host, const char* target_username,
    const char* target_password, const char* local_file_dir, const char* target_path)
{
    // ssh连接建立
    ssh_session session = ssh_create(target_host, target_username);
    if (session == NULL)return -1;

    // 身份验证 - 密码
    if (ssh_userauth_password(session, NULL, target_password) != SSH_AUTH_SUCCESS) {
        fprintf(stderr, "Failed to authenticate with password\n");
        ssh_disconnect(session);
        ssh_free(session);
        return -1;
    }

    // 传输
    int re = sftp_run(session, local_file_dir, target_path);

    return re;
}


int ssh_sftp_transmit_publickey(const char* target_host, const char* target_username,
    const char* local_file_dir, const char* target_path)
{
    // ssh连接建立
    ssh_session session = ssh_create(target_host, target_username);
    if (session == NULL)return -1;

    // 身份验证 - 密钥
    if (ssh_userauth_publickey_auto(session, NULL, NULL) != SSH_AUTH_SUCCESS) {
        fprintf(stderr, "Authentication failed: %s\n", ssh_get_error(session));
        ssh_disconnect(session);
        ssh_free(session);
        return -1;
    }

    // 传输
    int re = sftp_run(session, local_file_dir, target_path);

    return re;
}

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

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

相关文章

C语言 | Leetcode C语言题解之第2题两数相加

题目&#xff1a; 题解&#xff1a; struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {struct ListNode *head NULL, *tail NULL;int carry 0;while (l1 || l2) {int n1 l1 ? l1->val : 0;int n2 l2 ? l2->val : 0;int sum n1 n2 …

使用 Spring Email 和 Thymeleaf 技术,向新注册用户发送激活邮件(一)

这篇内容对应"2.1 发送邮件"小节 对应视频&#xff1a;9-发送邮件 视频链接 邮箱设置 需要去邮箱对应的官方客户端软件或网站开启IMAP/SMTP服务或POP3/SMTP服务器 如果不开启&#xff0c;就无法使用第三方用户代理&#xff0c;只能走第官方的电子邮件客户端软件或…

GT收发器第一篇_总体结构介绍

文章目录 前言GT收发器介绍 前言 之前写过一篇简单介绍GT的文章https://blog.csdn.net/m0_56222647/article/details/136730026&#xff0c;可以先通过这篇文章对整体进行简单了解一下。 GT收发器介绍 参考xilinx手册ug476 对于7系列的FPGA&#xff0c;共有3个系列&#xf…

3D检测:从pointnet,voxelnet,pointpillar到centerpoint

记录centerpoint学习笔记。目前被引用1275次&#xff0c;非常高。 地址&#xff1a;Center-Based 3D Object Detection and Tracking (thecvf.com) GitHub - tianweiy/CenterPoint CenterPoint&#xff1a;三维点云目标检测算法梳理及最新进展&#xff08;CVPR2021&#xff…

【Java初阶(七)】接口

❣博主主页: 33的博客❣ ▶文章专栏分类: Java从入门到精通◀ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; 目录 1.前言2.接口2.1语法规则2.2接口使用2.3接口特性2.4实现多个接口2.5接口使用实例2.6Clonable接口和深拷贝 3.Object类3.1对象比较equals方法3.2hashcod…

Vivado使用(1)——综合的约束与策略

目录 一、概述 二、约束与策略 2.1 约束 2.1.1 物理约束 2.1.2 时序约束 2.2 综合策略 2.2.1 flatten_hierarchy 2.2.2 gated_clock_conversion 2.2.3 bufg 2.2.4 fanout_limit 2.2.5 directive 2.2.6 retiming 2.2.7 fsm_extraction 2.2.8 keep_equivalent_regi…

Uibot6.0 (RPA财务机器人师资培训第6天 )发票验真机器人案例实战

类似于小北的这篇博客&#xff1a;Uibot (RPA设计软件&#xff09;Mage AI智能识别&#xff08;发票识别&#xff09;———课前材料五_uibot 添加mageai-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/135591297?spm1001.2014.3001.5501训练网站&#xff1a;泓江…

嵌入式科普(14)指针---这些年嵌入式工程师也不容易理解的词语

目录 一、指针&#xff08;Pointer&#xff09;&#xff1a; 1.1 动态内存管理&#xff1a; 1.2 数组和字符串操作&#xff1a; 1.3 函数参数传递&#xff1a; 1.4 数据结构实现&#xff08;链表&#xff09;&#xff1a; 1.5 实现回调函数&#xff1a; 1.6 提高性能&am…

Day63-LVS四层负载均衡及结合Nginx7层负载均衡实践

Day63-LVS四层负载均衡及结合Nginx7层负载均衡实践 1. LVS&#xff08;Linux Virtual Server&#xff09;介绍2. IPVS&#xff08;LVS&#xff09;发展史3. IPVS软件工作层次图4. LVS技术点小结5. LVS的4模式原理讲解5.1 NAT(Network AddressTranslation)&#xff0c;中文网络地…

纽扣电池CR1632没有电解决方案

使用环境 在使用小米的自拍杆时&#xff0c;发现纽扣电池没有电量了逛了下超市&#xff0c;结果发现都没有卖这个型号的电池&#xff0c;但是下午又要拍照&#xff0c;于是想起了应急的充电方法。声明一下&#xff0c;这个内置电池型号是CR1632&#xff0c;然而市面上&#xff…

vue基础教程(5)——十分钟吃透vue路由router

同学们可以私信我加入学习群&#xff01; 正文开始 前言一、路由概念二、路由使用三、创建路由对应的组件四、给整个项目一个入口总结 前言 前面的文章运行成功后&#xff0c;页面显示如下&#xff1a; 在这个页面中&#xff0c;点击Home和About都会切换右面的页面内容&#…

什么是Redis数据一致性?如何解决?

在系统中缓存最常用的策略是&#xff1a;服务端需要同时维护DB和cache&#xff0c;并且是以DB的结果为准–Cache-Aside Pattern&#xff08;缓存分离模式、旁路缓存&#xff09; 读数据 单纯的读数据是不会产生数据不一致&#xff0c;只有并发下读和写才会存在数据不一致。 写…

插入排序---算法

1、算法概念 插入排序&#xff1a;它的工作原理是通过构建有序排序&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置插入。 2、算法步骤 将第一待排序序列第一个元素看作一个有序序列&#xff0c;把第二个元素到最后一个元素当成是…

3万字80道Java基础经典面试题总结(2024修订版)

大家好&#xff0c;我是哪吒。 本系列是《10万字208道Java经典面试题总结(附答案)》的2024修订版。 目录 1、说说跨平台性2、Java是如何实现跨平台性的&#xff1f;3、JDK 和 JRE 有什么区别&#xff1f;4、为何要配置Java环境变量&#xff1f;5、Java都有哪些特性&#xff1f…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《偏远地区能源自洽系统源储容量协同配置方法》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

AcWing 4405. 统计子矩阵:做题笔记

目录 暴力思路 代码 前缀和双指针 代码 解释 推荐博客 这道题的主要思路就是枚举所有的子矩阵&#xff0c;判断符合条件的子矩阵的个数。 暴力思路 我服了&#xff0c;其实我最开始没有想到 &#xff1a;枚举所有的子矩阵 这样一个很有总结性的要点。 我是想着哦我先…

Mysql数据库:MHA高可用架构

目录 前言 一、MHA概述 1、什么是MHA 2、MHA的特点 3、MHA的组成 4、MHA的工作原理 5、故障切换备选主库的算法 二、部署MHA高可用架构 1、环境部署 2、部署主从同步 2.1 修改主配置文件并创建软链接 2.1.1 master 修改主配置文件并创建软连接 2.1.2 slave1 修改主…

WIFI驱动移植实验:将 rtl8188EUS驱动添加到 Linux 内核中

一. 简介 正点原子的 I.MX6U-ALPHA 开发板目前支持两种接口的 WIFI &#xff1a; USB 和 SDIO &#xff0c;其中 USB接口的WIFI 使用使用的芯片为 RTL8188EUS 或 RTL8188CUS &#xff0c; SDIO 接口的 WIFI 使用芯片为 RTL8189FS &#xff0c;也叫做 RTL8189FT…

尚医通day1

1 创建项目 doc 窗口 pnpm create vite 填写项目名 vue-syt选择框架 vuetypeScript 2整理项目 删除 /src/assets/vue.svg 文件&#xff0c;删除 /src/components 下的 helloWorld.vue删除app.vue内容&#xff0c;快捷键v3ts 生成模板内容去掉 /src/style.css 样式文件&…

仿微信领红包HTML源码

源码介绍 仿微信领红包HTML源码&#xff0c;将代码放到一个空白的HTML文件里面保存&#xff0c;鼠标双击即可查看效果&#xff0c;一个微信发送消息提示&#xff0c;弹窗就出来了&#xff0c;关闭之后&#xff0c;出现完整的微信红包领取界面&#xff0c;源码HTML&#xff0c;…