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

avatar
作者
猴君
阅读量:3

建立SSH会话并连接远端服务器

  • target_host:远端主机IP
  • target_username:远端主机用户名
ssh_session session;  // 连接SSH会话 session = ssh_new(); if (!session) {     fprintf(stderr, "Failed to create SSH session\n");     return -1; }  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 -1; } 

ssh_options_set() 函数设置会话的选项。最重要的选项是:

  • SSH_OPTIONS_HOST:要连接到的主机的名称
  • SSH_OPTIONS_PORT:使用的端口(默认为端口 22)
  • SSH_OPTIONS_USER:要连接的系统用户
  • SSH_OPTIONS_LOG_VERBOSITY:打印的消息数量

SSH身份验证

密码验证

直接传输密码即可 target_password即密码

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

密钥验证

生成密钥

  • 基于ED25519算法,生成密钥对命令如下:
ssh-keygen -t ed25519 -C "<注释内容>" 
  • 基于RSA算法,生成密钥对命令如下:
ssh-keygen -t rsa -C "<注释内容>" 

默认回车即可

查看密钥

ED25519 算法

cat ~/.ssh/id_ed25519.pub 

RSA 算法

cat ~/.ssh/id_rsa.pub 

拷贝密钥

Windows(WSLGit Bash):

cat ~/.ssh/id_ed25519.pub | clip 

Mac:

tr -d '\n' < ~/.ssh/id_ed25519.pub | pbcopy 

GNU/Linux (requires xclip):

xclip -sel clip < ~/.ssh/id_ed25519.pub 

复制到所需传入的服务器端的~/.ssh目录的authorized_keys文件里面

验证密钥是否正确

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

SFTP子系统构建

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

传输普通文件

  • local_file_path:本地需传文件路径
  • remote_file_path:传送至远端服务器路径
int sftp_normal_upload(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, S_IRUSR | S_IWUSR);     if (!file) {         fprintf(stderr, "Failed to open remote file: %s\n", remote_file_path);         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); } 

递归传输文件夹

sftp没有直接的传输文件夹的接口,我们需要递归目录来传输

假设有下面文件夹

           +-- file1    +-- B --+    |       +-- file2    A            |       +-- file3    +-- C --+            +-- file4 

打开目录 A -》进入子目录 B -》在 B 中创建文件 file1 -》在 B 中创建 file2 -》离开目录 B -》进入子目录 C -》在 C 语言中创建 file3 -》 在 C 语言中创建 file4 -》离开目录 C -》离开目录 A

本地遍历的时候,远端同时创建

  • local_path:本地路径
  • remote_path:远端路径
int sftp_recursive_upload(ssh_session session, sftp_session sftp, 				 const char* local_path, const char* remote_path) {     // 打开本地目录     DIR* local_dir = opendir(local_path);     if (!local_dir) {         fprintf(stderr, "Failed to open local directory: %s\n", local_path);         return -1;     }      // 创建服务器目录     sftp_mkdir(sftp, remote_path, S_IRWXU);      // 遍历本地目录项     struct dirent* entry;     while ((entry = readdir(local_dir)) != NULL) {         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {             continue; // Skip "." and ".."         }          // 构造全路径         char local_file_path[1024];         snprintf(local_file_path, sizeof(local_file_path), "%s/%s", local_path, entry->d_name);         char remote_file_path[1024];         snprintf(remote_file_path, sizeof(remote_file_path), "%s/%s", remote_path, entry->d_name);          // 如果本地条目是一个目录,递归上传它         if (entry->d_type == DT_DIR) {             sftp_recursive_upload(session, sftp, local_file_path, remote_file_path);         }         else { // 如果本地条目是一个普通文件,上传它             sftp_normal_upload(sftp, local_file_path, remote_file_path);         }     }      closedir(local_dir);     return 0; } 

完整传输小demo

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <libssh/libssh.h> #include <libssh/sftp.h> #include <dirent.h> #include <sys/stat.h> #include <fcntl.h>  const char* target_host = "xxx.xx.xxx.xxx"; const char* target_username = "AMY"; const char* target_password = "xxxxx";  int sftp_normal_upload(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, S_IRUSR | S_IWUSR);     if (!file) {         fprintf(stderr, "Failed to open remote file: %s\n", remote_file_path);         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); }  int sftp_recursive_upload(ssh_session session, sftp_session sftp, const char* local_path, const char* remote_path) {     // 打开本地目录     DIR* local_dir = opendir(local_path);     if (!local_dir) {         fprintf(stderr, "Failed to open local directory: %s\n", local_path);         return -1;     }      // 创建服务器目录     sftp_mkdir(sftp, remote_path, S_IRWXU);      // 遍历本地目录项     struct dirent* entry;     while ((entry = readdir(local_dir)) != NULL) {         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {             continue; // Skip "." and ".."         }          // 构造全路径         char local_file_path[1024];         snprintf(local_file_path, sizeof(local_file_path), "%s/%s", local_path, entry->d_name);         char remote_file_path[1024];         snprintf(remote_file_path, sizeof(remote_file_path), "%s/%s", remote_path, entry->d_name);          // 如果本地条目是一个目录,递归上传它         if (entry->d_type == DT_DIR) {             sftp_recursive_upload(session, sftp, local_file_path, remote_file_path);         }         else { // 如果本地条目是一个普通文件,上传它             sftp_normal_upload(sftp, local_file_path, remote_file_path);         }     }      closedir(local_dir);     return 0; }  int main() {     ssh_session session;     sftp_session sftp;      // 连接SSH会话     session = ssh_new();     if (!session) {         fprintf(stderr, "Failed to create SSH session\n");         return -1;     }      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 -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;     }      // 打开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[1024];     getcwd(local_dir, sizeof(local_dir));     printf("请输入所需传入的文件或目录的名字\n");     int len = strlen(local_dir);     local_dir[len] = '/';     local_dir[len + 1] = '\0';      char filename[100];     scanf("%s", filename);     strcat(local_dir, filename);      struct stat file_stat;      // 获取文件的详细信息     if (stat(local_dir, &file_stat) != 0) {         perror("stat");         return -1;     }      printf("请输入所需传入远端路径\n");     char target_path[1024];     scanf("%s", target_path);      // 判断文件类型      //普通文件     if (S_ISREG(file_stat.st_mode)) {         sftp_normal_upload(sftp, local_dir, target_path);     }     //目录文件     else if (S_ISDIR(file_stat.st_mode)) {         // 递归上传本地目录到远程目录         if (sftp_recursive_upload(session, sftp, local_dir, target_path) != 0) {             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 0; } 

在这里插入图片描述

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!