如何将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




