SSH连接SFTP传输:如何使用libssh库在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

解压压缩包,进入目录,在当前页面右键打开终端

执行以下命令:

bash 复制代码
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)

c 复制代码
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;
}
相关推荐
梓仁沐白3 小时前
ubuntu+windows双系统切换后蓝牙设备无法连接
windows·ubuntu
九鼎科技-Leo7 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
Yang.999 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
我不瘦但很逗9 小时前
Windows下使用DBeaver连接云数据库(MySQL)
数据库·windows
ashane131411 小时前
Java list
java·windows·list
万里沧海寄云帆11 小时前
Word 插入分节符页码更新问题
windows·microsoft·word
dot.Net安全矩阵12 小时前
.NET 通过模块和驱动收集本地EDR的工具
windows·安全·web安全·.net·交互
编程修仙13 小时前
Collections工具类
linux·windows·python
程序员小羊!15 小时前
高级 SQL 技巧讲解
windows
xiangshangdemayi16 小时前
Windows环境GeoServer打包Docker极速入门
windows·docker·容器·geoserver·打包·数据挂载