SSH.NET连接本地SFTP服务器遇System.ObjectDisposedException错误求助
SSH.NET上传SFTP报错:Safe handle has been closed 问题修复
嘿,我看你用SSH.NET上传文件时碰到了System.ObjectDisposedException和Socket连接异常,好在命令行和FileZilla能正常连,说明SFTP服务本身没问题,问题大概率出在代码的资源管理和连接逻辑上。下面给你拆解几个关键问题点,以及修改后的代码:
核心问题分析
- 缓冲区设置时机不对:你在每次上传文件时才设置
client.BufferSize,频繁修改缓冲区会干扰底层Socket的资源状态,应该在连接建立后一次性设置好。 - 路径拼接不规范:用
+ "/" +拼接路径在跨平台环境(比如你用的Mono)容易出问题,换成Path.Combine更稳妥。 - 冗余资源占用:代码里声明了
SQLiteConnection但完全没用到,这会占用不必要的资源,建议清理掉。 - 缺少异常处理:没有捕获连接或上传过程中的异常,一旦出错就直接抛出未处理异常,导致资源无法正常释放。
修改后的完整代码
public static void UploadToSFTP(List<string> selectedFileList) { // 清理未使用的SQLiteConnection,减少资源占用 string host = "myiphere"; int port = 22; string username = "gth"; string password = "1234"; string remoteDir = @"/D/SFTP"; // Using语句确保SftpClient自动释放资源,但内部也要做好异常处理 using (var client = new SftpClient(host, port, username, password)) { try { client.Connect(); // 连接成功后立即设置缓冲区,不要在循环内重复操作 client.BufferSize = 4 * 1024; // 可选:先检查远程目录是否存在,不存在就创建 if (!client.Exists(remoteDir)) { client.CreateDirectory(remoteDir); } client.ChangeDirectory(remoteDir); foreach (var file in selectedFileList) { string localFilePath = Path.Combine(testPath, file); // 先检查本地文件是否存在,避免后续FileStream报错 if (!File.Exists(localFilePath)) { Console.WriteLine($"跳过:本地文件不存在 -> {localFilePath}"); continue; } using (var fs = new FileStream(localFilePath, FileMode.Open, FileAccess.Read)) { string remoteFileName = Path.GetFileName(localFilePath); Console.WriteLine($"开始上传:{remoteFileName}"); // 可选:添加上传进度回调,方便排查问题 client.UploadFile(fs, remoteFileName, (uploadedBytes) => { Console.WriteLine($"进度:{uploadedBytes}/{fs.Length} bytes"); }); } } // 显式断开连接,确保Socket资源正常释放 client.Disconnect(); } catch (SocketException ex) { Console.WriteLine($"连接异常:{ex.Message}"); // 这里可以加重试逻辑,比如重试1-2次 } catch (SftpException ex) { Console.WriteLine($"SFTP操作错误:{ex.Message}"); } catch (Exception ex) { Console.WriteLine($"未知错误:{ex.Message}\n{ex.StackTrace}"); } } }
额外排查小贴士
- 确认
testPath变量是否正确初始化,指向本地文件的实际目录。 - 如果你在Mono环境运行,检查SSH.NET版本是否适配当前Mono版本,尽量用最新稳定版。
- 可以给连接加超时设置:
client.ConnectionInfo.Timeout = TimeSpan.FromSeconds(30);,避免因超时导致Socket异常。 - 查看SFTP服务器的日志,确认是否有连接被强制断开的记录(比如防火墙限制、用户权限问题)。
内容的提问来源于stack exchange,提问作者Goh Han
相关产品推荐
相关产品推荐

