如何用Rust实现SFTP文件上传?现有方案遇问题求助
Rust实现SFTP文件上传问题
需求
- 用Rust代码实现向SFTP服务器上传文件
- 找到
openssh-sftp-clientcrate,但因文档匮乏无法上手 - 禁止使用
sftp/rftp等命令行工具
已尝试的Crate及问题
1. ssh2 crate
代码示例:
use std::io::prelude::*; use std::net::TcpStream; use std::path::Path; use ssh2::Session; // 连接SSH服务器 let tcp = TcpStream::connect("SFTP_IP:PORT").unwrap(); let mut sess = Session::new().unwrap(); sess.set_tcp_stream(tcp); sess.handshake().unwrap(); sess.userauth_agent("username").unwrap(); // 写入文件 let mut remote_file = sess.scp_send(Path::new("remote"), 0o644, 10, None).unwrap(); remote_file.write(b"1234567890").unwrap(); // 关闭通道并等待传输完成 remote_file.send_eof().unwrap(); remote_file.wait_eof().unwrap(); remote_file.close().unwrap(); remote_file.wait_close().unwrap();
错误:认证失败。问题出在使用userauth_agent认证方式,若服务器不支持agent认证或本地无可用agent,就会触发该错误;同时这段代码用的是SCP协议而非SFTP,不符合需求。
2. rust-ftp crate
代码示例:
use std::str; use std::io::Cursor; use ftp::FtpStream; fn main() { // 连接FTP服务器并认证 let mut ftp_stream = FtpStream::connect("SFTP_IP:PORT").unwrap(); let _ = ftp_stream.login("username", "password").unwrap(); // 获取当前目录 println!("Current directory: {}", ftp_stream.pwd().unwrap()); // 切换目录 let _ = ftp_stream.cwd("test_data").unwrap(); // 下载文件 let remote_file = ftp_stream.simple_retr("ftpext-charter.txt").unwrap(); println!("Read file with contents {} ", str::from_utf8(&remote_file.into_inner()).unwrap()); // 上传文件 let mut reader = Cursor::new("Hello from the Rust \"ftp\" crate!".as_bytes()); let _ = ftp_stream.put("greeting.txt", &mut reader); println!("Successfully wrote greeting.txt"); // 断开连接 let _ = ftp_stream.quit(); }
错误:无法连接服务器。原因是rust-ftp是专门用于FTP协议的库,而SFTP是基于SSH的完全不同的协议,两者不兼容,因此无法通过该库连接SFTP服务器。
可行解决方案
方案1:使用ssh2 crate实现SFTP
ssh2原生支持SFTP协议,修正后的代码如下:
use std::io::prelude::*; use std::net::TcpStream; use ssh2::Session; fn main() -> Result<(), Box<dyn std::error::Error>> { // 连接SSH服务器(SFTP默认端口为22) let tcp = TcpStream::connect("SFTP_IP:22")?; let mut sess = Session::new()?; sess.set_tcp_stream(tcp); sess.handshake()?; // 替换为你的用户名和密码,或改用密钥认证 sess.userauth_password("your_username", "your_password")?; // 确认认证成功 assert!(sess.authenticated()); // 初始化SFTP会话 let sftp = sess.sftp()?; // 创建并写入远程文件 let mut remote_file = sftp.create("/remote/path/your_file.txt")?; remote_file.write_all(b"Content to upload")?; remote_file.close()?; println!("文件上传成功"); Ok(()) }
方案2:使用openssh-sftp-client crate
该库基于OpenSSH实现异步SFTP操作,示例代码如下:
use openssh_sftp_client::SftpClient; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // 建立SSH连接:格式为 "用户名@服务器地址:端口" let client = SftpClient::connect("your_username@SFTP_IP:22", None).await?; // 上传本地文件到远程路径 client.upload("/local/path/your_file.txt", "/remote/path/your_file.txt").await?; println!("文件上传成功"); Ok(()) }
注意事项:
- 需要在
Cargo.toml中添加依赖:openssh-sftp-client = "0.1.5"(版本号请以最新为准) - 若使用密钥认证,可将第二个参数改为私钥路径,例如
Some("/home/user/.ssh/id_rsa")
内容的提问来源于stack exchange,提问作者Hamza Zubair
相关产品推荐
相关产品推荐

