You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何将Renci.SshNet的SshClient转换为SftpClient?复用连接实现多操作

如何复用Renci.SshNet的SSH连接同时执行命令和文件传输?

嘿,这个问题我刚好处理过!你完全不需要创建多个SSH连接,Renci.SshNet支持复用已有的连接来同时处理命令执行和SFTP操作,下面给你两种靠谱的实现方式:

方式一:复用已连接SshClient的会话(无需额外创建ConnectionInfo)

这种方式适合你已经初始化了SshClient并完成连接的场景,核心是通过反射获取SshClient内部的已连接会话(Session),用它来实例化SftpClient,直接复用当前连接:

using System.IO;
using System.Reflection;
using Renci.SshNet;

using (var sshClient = new SshClient("someDomain.com", 22, "root", new PrivateKeyFile(@"C:\Path\To\PrivateKey\id_rsa")))
{
    // 建立SSH连接
    sshClient.Connect();

    // 先执行命令操作
    var commandResult = sshClient.RunCommand("echo 'hello world' > /root/test.txt");
    // 可以查看命令执行结果
    Console.WriteLine($"命令执行输出:{commandResult.Result}");
    Console.WriteLine($"命令执行错误:{commandResult.Error}");

    // 通过反射获取SshClient内部的Session(因为Session属性是internal的)
    var sessionProperty = sshClient.GetType().GetProperty(
        "Session", 
        BindingFlags.NonPublic | BindingFlags.Instance
    );
    var session = sessionProperty.GetValue(sshClient) as Session;

    // 使用已有的Session创建SftpClient,复用同一个连接
    using (var sftpClient = new SftpClient(session))
    {
        // 注意:这里千万不要调用sftpClient.Connect()!Session已经处于连接状态了
        // 执行文件上传操作
        using (var localFileStream = File.OpenRead(@"C:\Local\Files\example.txt"))
        {
            sftpClient.UploadFile(localFileStream, "/root/uploaded_example.txt");
            Console.WriteLine("文件上传完成");
        }

        // 或者执行文件下载操作
        using (var localFileStream = File.Create(@"C:\Local\Files\downloaded_test.txt"))
        {
            sftpClient.DownloadFile("/root/test.txt", localFileStream);
            Console.WriteLine("文件下载完成");
        }
    }

    // 最后断开SSH连接
    sshClient.Disconnect();
}

方式二:提前创建ConnectionInfo(更稳妥,无需反射)

如果你还没初始化SshClient,推荐用这种方式:先创建一个ConnectionInfo对象,用它同时初始化SshClient和SftpClient,这样两个客户端会自动复用同一个连接池里的活跃连接,不需要依赖反射,兼容性更好:

using System.IO;
using Renci.SshNet;

// 先创建连接信息对象,包含所有认证参数
var authMethod = new PrivateKeyAuthenticationMethod(
    "root", 
    new PrivateKeyFile(@"C:\Path\To\PrivateKey\id_rsa")
);
var connectionInfo = new ConnectionInfo(
    "someDomain.com", 
    22, 
    "root", 
    authMethod
);

using (var sshClient = new SshClient(connectionInfo))
{
    sshClient.Connect();

    // 执行命令
    var commandResult = sshClient.RunCommand("echo 'hello world' > /root/test.txt");
    Console.WriteLine($"命令执行结果:{commandResult.Result}");

    // 用同一个ConnectionInfo创建SftpClient并连接
    using (var sftpClient = new SftpClient(connectionInfo))
    {
        sftpClient.Connect(); // 这里会复用已有的SSH连接,不会新建TCP连接
        // 执行文件操作
        using (var localStream = File.OpenRead(@"C:\Local\Files\test_upload.txt"))
        {
            sftpClient.UploadFile(localStream, "/root/uploaded_file.txt");
        }
        sftpClient.Disconnect();
    }

    sshClient.Disconnect();
}

关键注意事项

  • 不管用哪种方式,都要确保在使用SftpClient期间,SshClient的连接是保持活跃的,不要提前断开
  • 方式一中不要调用SftpClient.Connect(),否则会尝试新建连接,反而达不到复用的目的
  • 方式二的兼容性更好,不会因为Renci.SshNet版本更新导致反射失效,更推荐在新项目中使用

内容的提问来源于stack exchange,提问作者Tono Nam

火山引擎 最新活动