Renci SSH .NET SFTP服务器无剩余空间时上传挂起无异常问题咨询
问题成因
- Renci SSH.NET 中
SftpClient.ConnectionTimeout仅作用于SSH连接建立阶段,文件上传属于后续业务操作,默认OperationTimeout为-1(无限等待),只要TCP连接未被主动断开,同步UploadFile方法就会持续阻塞。 - 多数SFTP服务端在磁盘空间不足时,不会主动断开连接或返回错误报文,仅会暂停接收上传数据、保持连接存活,因此客户端不会触发任何异常,进入永久挂起状态。
- 服务端生成的0字节文件是上传初始化阶段创建的占位文件,实际写入操作触发磁盘容量限制后被挂起,没有数据写入磁盘。
防范方案
1. 配置操作层面超时
显式设置SftpClient.OperationTimeout,覆盖默认无限等待配置,上传操作超过阈值后会自动抛出SshOperationTimeoutException,示例如下:
try { using (var client = new SftpClient(account.Host, account.Username, new[] { privateKey })) { // 设置所有SFTP操作超时时间为5分钟,可根据业务场景调整 client.OperationTimeout = TimeSpan.FromMinutes(5); using (var fileStream = File.OpenRead(localFilePath)) { client.Connect(); var remoteDir = $"/{account.DirectoryPath}/{ftpDirectory}"; if (!client.Exists(remoteDir)) { client.CreateDirectory(remoteDir); } client.UploadFile(fileStream, ftpFilePath); client.Disconnect(); } } } catch (Exception ex) { // 异常处理逻辑 }
2. 添加上传进度监控
使用UploadFile的进度回调重载,监控上传进度变化,若长时间无进度更新则主动断开连接:
var lastProgressUpdate = DateTime.Now; client.UploadFile(fileStream, ftpFilePath, uploadedBytes => { lastProgressUpdate = DateTime.Now; // 可配合后台线程检测lastProgressUpdate的间隔,超过阈值主动调用client.Disconnect()终止上传 });
3. 上传前预校验磁盘空间(仅适用于类Unix服务器)
若SFTP账号拥有Shell执行权限,可通过执行df命令获取目标目录剩余磁盘空间,提前判断是否支持当前文件上传:
// 获取远程目录剩余空间,单位为字节 long GetRemoteFreeSpace(SftpClient client, string remoteDir) { var dfCmd = client.Execute($"df -k {remoteDir} | awk 'NR==2{{print $4}}'"); if (dfCmd.ExitStatus != 0 || !long.TryParse(dfCmd.Result.Trim(), out var freeKb)) { return -1; // 无权限获取或命令执行失败,跳过校验 } return freeKb * 1024; } // 调用逻辑 var localFileSize = new FileInfo(localFilePath).Length; var remoteFreeSpace = GetRemoteFreeSpace(client, $"/{account.DirectoryPath}/{ftpDirectory}"); if (remoteFreeSpace != -1 && remoteFreeSpace < localFileSize) { // 提前抛出磁盘空间不足异常,终止上传流程 throw new IOException("远程服务器磁盘空间不足,无法上传文件"); }
4. 异常场景补充清理逻辑
在超时或上传失败的异常分支中,主动删除服务端生成的0字节占位文件,避免垃圾文件残留:
catch (SshOperationTimeoutException ex) { if (client.IsConnected) { if (client.Exists(ftpFilePath)) { client.DeleteFile(ftpFilePath); } client.Disconnect(); } // 其他业务处理逻辑 }
内容的提问来源于stack exchange,提问作者pitersmx
相关产品推荐
相关产品推荐

