Rust russh实现SSH透传程序遇所有权错误求助
问题解决:Rust SSH透传中的所有权错误及实现修正
错误原因
你遇到的borrow of moved value: 'channel'错误,是因为你将channel的所有权完全转移到了tokio::spawn启动的异步任务中,后续代码试图再次访问channel时,该变量的所有权已不在当前作用域内,违反了Rust的所有权规则。
能否复制Channel?
不行。russh::Channel没有实现Clone trait,无法直接复制。异步环境下共享可变资源的标准做法是使用**Arc<Mutex<Channel>>**:
Arc(原子引用计数)允许多个异步任务共享同一个资源的所有权Mutex(互斥锁)保证同一时间只有一个任务能访问可变的Channel,避免并发冲突
修正后的代码
use std::sync::Arc; use tokio::io::{stdin, AsyncBufReadExt, BufReader}; use tokio::sync::Mutex; use russh::client; use russh::ChannelMsg; use std::net::SocketAddr; use std::time::Duration; use russh_keys::load_secret_key; async fn start_ssh_driver(host: String, user: String, private_key_path: String, run_command: String) -> Result<(), Box<dyn std::error::Error>> { // 建立SSH会话 let key_pair = load_secret_key(private_key_path, None)?; let config = client::Config { connection_timeout: Some(Duration::from_secs(5)), ..<_>::default() }; let config = Arc::new(config); let sh = client::Client {}; let mut session = client::connect(config, SocketAddr::from_str(&host)?, sh).await?; let _auth_res = session .authenticate_publickey(user, Arc::new(key_pair)) .await?; // 创建Channel并包装为Arc<Mutex>实现多任务共享 let channel = Arc::new(Mutex::new(session.channel_open_session().await?)); // 启动异步任务读取远程命令的输出 let channel_clone = Arc::clone(&channel); tokio::spawn(async move { println!("Waiting for remote output..."); let mut channel = channel_clone.lock().await; while let Some(msg) = channel.wait().await { match msg { ChannelMsg::Data { ref data } => { if let Ok(v) = std::str::from_utf8(data) { print!("{}", v); } } ChannelMsg::Eof => { println!("\nRemote command exited"); break; } _ => {} } } }); // 执行目标远程命令 { let mut channel = channel.lock().await; channel.exec(false, &run_command).await?; } // 读取本地stdin并透传到远程命令的stdin let stdin = stdin(); let mut reader = BufReader::new(stdin); let mut line = String::new(); loop { print!("> "); let n = reader.read_line(&mut line).await?; if n == 0 { // 本地输入关闭,发送EOF通知远程 let mut channel = channel.lock().await; channel.eof().await?; break; } // 将本地输入发送到远程 let mut channel = channel.lock().await; channel.data(line.as_bytes()).await?; line.clear(); } Ok(()) }
关键修正点
- 共享Channel:用
Arc<Mutex<Channel>>包装Channel,通过克隆Arc让异步任务和主任务共享访问权 - 纠正透传逻辑:仅在启动时调用一次
exec执行目标命令,后续通过channel.data()将本地输入发送到远程命令的stdin,实现真正的流透传 - 错误处理优化:替换
unwrap()为?,让错误向上传播,符合Rust最佳实践 - 输出格式优化:用
print!替代println!,避免破坏远程输出的原有格式
内容的提问来源于stack exchange,提问作者Khadim Fall
相关产品推荐
相关产品推荐

