You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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(())
}

关键修正点

  1. 共享Channel:用Arc<Mutex<Channel>>包装Channel,通过克隆Arc让异步任务和主任务共享访问权
  2. 纠正透传逻辑:仅在启动时调用一次exec执行目标命令,后续通过channel.data()将本地输入发送到远程命令的stdin,实现真正的流透传
  3. 错误处理优化:替换unwrap()为?,让错误向上传播,符合Rust最佳实践
  4. 输出格式优化:用print!替代println!,避免破坏远程输出的原有格式

内容的提问来源于stack exchange,提问作者Khadim Fall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 00:35:17