SFTP大文件上传时服务器断开连接求助(Azure函数+C#)
解决SFTP大文件上传被服务器断开连接的问题
问题背景
用C#开发的Azure Function App,通过SSH.NET 2020.0.1包上传文件到SFTP服务器。小文件上传正常,但3-5GB的大文件上传时,服务器会主动断开连接,报错:
Sftp file transfer failed. File:Import/test.zip Error: Connection was closed by the server.
原代码:
public async Task UploadFile(BlockBlobClient client, string destination) { try { using var inputStream = await client.OpenReadAsync(); inputStream.Position = 0; if (!_sftpClient.IsConnected) { _sftpClient.Connect(); } _sftpClient.UploadFile(inputStream, destination); } catch (Exception ex) { _log.LogError("transfer failed {msg}",ex.Message); } finally { _sftpClient.Disconnect(); } }
解决方案
1. 改用分块上传(核心修复)
SSH.NET默认的UploadFile是一次性传输整文件,大文件传输耗时太长,容易触发服务器超时。改成分块传输,把文件拆成小块发送,还能避免连接长时间闲置。
修改后的代码:
public async Task UploadFile(BlockBlobClient client, string destination) { try { using var inputStream = await client.OpenReadAsync(); inputStream.Position = 0; if (!_sftpClient.IsConnected) { _sftpClient.Connect(); } // 设置分块大小(示例为10MB,可根据服务器配置调整) var bufferSize = 10 * 1024 * 1024; using var uploadStream = _sftpClient.Create(destination); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = await inputStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await uploadStream.WriteAsync(buffer, 0, bytesRead); // 每块传输后刷新,确保数据及时发送,避免连接闲置 uploadStream.Flush(); } } catch (Exception ex) { _log.LogError("transfer failed {msg}", ex.Message); _log.LogError("Full exception: {ex}", ex); // 建议记录完整异常栈,方便排查 } finally { if (_sftpClient.IsConnected) { _sftpClient.Disconnect(); } } }
2. 开启SSH连接心跳
设置KeepAlive间隔,防止服务器因为长时间无数据交互断开连接。初始化SftpClient时添加配置:
// 示例:每30秒发送一次心跳包 _sftpClient = new SftpClient(host, port, username, password); _sftpClient.KeepAliveInterval = TimeSpan.FromSeconds(30);
3. 调整Azure Function超时时间
Azure Function消费计划默认超时5分钟,大文件上传肯定不够用。在host.json里修改超时配置:
{ "functionTimeout": "02:00:00" // 设置为2小时,根据实际传输时长调整 }
注意:消费计划最大超时是10分钟,如果需要更长时间,得切换到高级计划或专用计划。
4. 排查SFTP服务器限制
联系SFTP服务器管理员确认:
- 是否有单个文件大小限制
- 连接超时时间设置
- 是否允许分块传输大文件
5. 优化Blob读取方式(可选)
直接读取Blob流可能有内存压力,建议先把Blob下载到Azure Function的临时存储,再上传到SFTP:
public async Task UploadFile(BlockBlobClient client, string destination) { try { // 下载到临时文件 var tempFilePath = Path.GetTempFileName(); await client.DownloadToAsync(tempFilePath); if (!_sftpClient.IsConnected) { _sftpClient.Connect(); } using var fileStream = new FileStream(tempFilePath, FileMode.Open, FileAccess.Read); var bufferSize = 10 * 1024 * 1024; using var uploadStream = _sftpClient.Create(destination); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await uploadStream.WriteAsync(buffer, 0, bytesRead); uploadStream.Flush(); } // 删除临时文件 File.Delete(tempFilePath); } catch (Exception ex) { _log.LogError("transfer failed {msg}", ex.Message); _log.LogError("Full exception: {ex}", ex); } finally { if (_sftpClient.IsConnected) { _sftpClient.Disconnect(); } } }
内容的提问来源于stack exchange,提问作者suraj_123
相关产品推荐
相关产品推荐

