SSH连接SFTP传输:如何使用libssh库在Linux环境下进行(文件、文件夹)传输到远端服务器
创始人
2025-01-20 20:02:56
0次

  • 建立SSH会话并连接远端服务器
  • SSH身份验证
    • 密码验证
    • 密钥验证
      • 生成密钥
      • 查看密钥
      • 拷贝密钥
      • 验证密钥是否正确
  • SFTP子系统构建
  • 传输普通文件
  • 递归传输文件夹
  • 完整传输小demo

建立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(在WSL或Git 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  #include  #include  #include  #include  #include  #include  #include   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; } 

在这里插入图片描述

相关内容

热门资讯

实测交流透视挂!宝玛大厅ai智... 实测交流透视挂!宝玛大厅ai智能透视挂教程,宝玛大厅破解软件经验(本来有挂辅助)1、每一步都需要思考...
总算了解辅助器!朱雀吴江三缺一... 总算了解辅助器!朱雀吴江三缺一ai智能透视辅助挂技巧,朱雀吴江三缺一好像是有挂(有辅助挂细节)朱雀吴...
今日公布透视!九五至尊大厅ai... 今日公布透视!九五至尊大厅ai智能透视插件,九五至尊大厅有没有透视挂窍门(切实有挂技术)1、在九五至...
玩家必看科普开挂!聚闲麻将ai... 玩家必看科普开挂!聚闲麻将ai智能透视辅助挂软件,聚闲麻将总是真的有挂(有辅助挂方式)聚闲麻将能透视...
据报道开挂!旅游娱乐ai智能开... 据报道开挂!旅游娱乐ai智能开挂工具,旅游娱乐辅助工具演示(一直有挂教学)1、全新机制【旅游娱乐ai...
一分钟揭秘开挂!决胜朋来麻将a... 一分钟揭秘开挂!决胜朋来麻将ai智能透视辅助挂教程,决胜朋来麻将真是真的是有挂(有辅助挂总结)1、首...
如何分辨真伪透视!红牛ai智能... 如何分辨真伪透视!红牛ai智能透视攻略,红牛是不是有挂经验(真是有挂技术)1、操作简单,无需红牛手机...
2分钟细说辅助器!江湖大庆麻将... 2分钟细说辅助器!江湖大庆麻将ai智能透视辅助挂攻略,江湖大庆麻将竟然是真的有挂(有辅助挂头条)1、...
总算清楚透视挂!老夫子厅ai智... 总算清楚透视挂!老夫子厅ai智能透视挂技巧,老夫子厅怎么开挂课程(好像发现有挂)老夫子厅破解侠是真的...
解密关于辅助!菜鸟麻将ai智能... 解密关于辅助!菜鸟麻将ai智能透视辅助挂脚本,菜鸟麻将总是存在有挂(有辅助挂存在)1、用户打开应用后...