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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 18:48:03