FtpWebRequest 30分钟超时

Igo*_*gor 19 .net c# ftp filezilla ftpwebrequest

我的代码在通过FTP下载大文件30分钟后遇到超时异常.服务器是在Windows上运行的FileZilla.我们有一个配置了选项Enable FTP over SSL/TLS support (FTPS)Allow explicit FTP over TLS启用的SSL证书.我可以访问服务器和FileZilla配置,但看不到任何可能导致此行为的内容.下面是在Windows 2012 Server Machine上运行在.NET 4.6.2上的源代码.它可以从FTP服务器下载文件,但如果文件下载时间超过30分钟,则会在30分钟后超时(如下所列).

作为测试,我使用从同一客户端PC运行的FileZilla Client,同时从同一服务器端点下载多个大文件,以便每个文件的下载花费超过30分钟来完成.此方案中未发生任何错误.

我在StackOverflow以及Google上搜索过,但没有任何有希望的东西出现.如果有人有一些关于在哪里看(服务器端或客户端)的提示,我将非常感激.


应用代码

public class FtpFileDownloader
{
    // log4net
    private static readonly ILog Logger = LogManager.GetLogger(typeof(FtpFileDownloader));

    public void DownloadFile()
    {
        // setting the SecurityProtocol did not change the outcome, both were tried. Originally it was not set at all.
        // ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;


        ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;

        const int timeout = 7200000;
        const string file = "some-existing-file";
        try
        {
            var request = (FtpWebRequest) WebRequest.Create("uri-path-to-file");
            request.KeepAlive = false;
            request.Timeout = -1;
            request.ReadWriteTimeout = timeout;

            request.Credentials = new NetworkCredential("userName", "password");
            request.UsePassive = true;
            request.EnableSsl = true;
            request.Method = WebRequestMethods.Ftp.DownloadFile;

            Logger.Debug($"Downloading '{file}'");
            using (var response = (FtpWebResponse) request.GetResponse())
            using (var sourceStream = response.GetResponseStream())
            using (var targetStream = new FileStream("some-target-on-disk", FileMode.Create, FileAccess.Write))
            {
                try
                {
                    sourceStream.CopyTo(targetStream);
                    targetStream.Flush();
                    Logger.Debug($"Finished download '{file}'");
                }
                catch (Exception exInner)
                {
                    Logger.Error($"Error occurred trying to download file '{file}'.", exInner);
                }
            }
        }
        catch (Exception ex)
        {
            Logger.Error($"Error occurred trying to dispose streams when downloading file '{file}'.", ex);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

应用日志

ERROR FtpFileDownloader - Error occurred trying to download file 'some-existing-file'.
System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
   at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
   at System.Net.Security._SslStream.StartFrameBody(Int32 readBytes, Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security._SslStream.StartFrameHeader(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security._SslStream.StartReading(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security._SslStream.ProcessRead(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.TlsStream.Read(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.FtpDataStream.Read(Byte[] buffer, Int32 offset, Int32 size)
   at System.IO.Stream.InternalCopyTo(Stream destination, Int32 bufferSize)
   at System.IO.Stream.CopyTo(Stream destination)
   at FtpFileDownloader.DownloadFile

ERROR FtpFileDownloader - Error occurred trying to dispose streams when downloading file 'some-existing-file'.
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive.
   at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
   at System.Net.FtpWebRequest.RequestCallback(Object obj)
   at System.Net.CommandStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at System.IO.Stream.Dispose()
   at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
   at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
   at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
   at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
   at System.Net.FtpWebRequest.RequestCallback(Object obj)
   at System.Net.CommandStream.Abort(Exception e)
   at System.Net.CommandStream.CheckContinuePipeline()
   at System.Net.FtpWebRequest.DataStreamClosed(CloseExState closeState)
   at System.Net.FtpDataStream.System.Net.ICloseEx.CloseEx(CloseExState closeState)
   at System.Net.FtpDataStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at System.IO.Stream.Dispose()
   at FtpFileDownloader.DownloadFile
Run Code Online (Sandbox Code Playgroud)

FileZilla - 常规设置

 Listen on these ports: 21
  Max. number of users: 0 (infinite)
     Number of threads: 2
    Connection timeout: 120 (seconds)
   No Transfer timeout: 9000 (seconds)
           Log timeout: 60 (seconds)
Run Code Online (Sandbox Code Playgroud)

FileZilla服务器日志

23-2-2018 11:40:40 - (not logged in) (194.123.75.2)> Connected on port 21, sending welcome message...
23-2-2018 11:40:40 - (not logged in) (194.123.75.2)> 220 Welcome
23-2-2018 11:40:40 - (not logged in) (194.123.75.2)> AUTH TLS
23-2-2018 11:40:40 - (not logged in) (194.123.75.2)> 234 Using authentication type TLS
23-2-2018 11:40:40 - (not logged in) (194.123.75.2)> TLS connection established
23-2-2018 11:40:40 - (not logged in) (194.123.75.2)> USER  my-user-account
23-2-2018 11:40:40 - (not logged in) (194.123.75.2)> 331 Password required for my-user-account
23-2-2018 11:40:40 - (not logged in) (194.123.75.2)> PASS **************
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> 230 Logged on
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> PBSZ 0
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> 200 PBSZ=0
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> PROT P
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> 200 Protection level set to P
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> OPTS utf8 on
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> 202 UTF8 mode is always enabled. No need to send this command.
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> PWD
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> 257 "/" is current directory.
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> TYPE I
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> 200 Type set to I
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> PASV
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> 227 Entering Passive Mode (IP-ADDRESS,245,222)
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> RETR path-to-file
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> 150 Opening data channel for file download from server of "/path-to-file"
23-2-2018 11:40:40 - my-user-account (194.123.75.2)> TLS connection for data connection established
23-2-2018 12:10:41 - my-user-account (194.123.75.2)> disconnected.
Run Code Online (Sandbox Code Playgroud)

请注意断开连接(最后一行)和它之前的行之间有30分钟.如果它已成功完成转移,那么226 Successfully transferred "/path-to-file"在该disconnected行之前也会有一行读取


进度更新:

  • (2018.02.20)我要求我们的网络团队检查防火墙规则,但他们找不到任何有趣的东西.
  • (2018.02.22)我发现正在使用的FileZilla Server的版本是0.9.43 beta(根据更改日志发布日期2014-01-02).虽然我没有在更改日志中发现任何表明此行为曾经是一个固定的错误,但我将升级到最新版本0.9.60.2(发布日期2017-02-08)并再次执行测试.将在24小时内回复.
  • (2018.02.23)FileZilla已更新至最新版本.这没有解决问题,我更新了服务器日志,但它看起来几乎与之前的日志完全相同,除了最后一次传输是通过TLS而不是SSL进行的.
  • (2018.02.23)我在FileZilla支持页面上找到以下链接超大文件的超时.我将把它推回给我们托管服务提供商的网络工作人员再看看.
  • (2018.02.27)事实证明,公司防火墙(客户端执行的网络)而不是托管防火墙(托管FileZilla的网络)是罪魁祸首.它被配置为在1800几秒钟后丢弃空闲连接.已添加规则以在这两个端点之间覆盖此规则.

罪魁祸首/答案

事实证明,公司防火墙(客户端执行的网络)而不是托管防火墙(托管FileZilla的网络)是罪魁祸首.它被配置为在1800几秒钟后丢弃空闲连接.已添加规则以在这两个端点之间覆盖此规则.

Leo*_*lev 8

您可能应该尝试另一种不基于的FTP协议客户端实现FtpWebRequest.

相关问题已存在很长时间,他们没有明确的解决方案或答案.所以我会尝试类似FluentFTP的东西,它直接使用Winsock API.XML文档注释表明DownloadFile()应该很好地处理大文件下载:

/// <summary>
/// Downloads the specified file onto the local file system.
/// High-level API that takes care of various edge cases internally.
/// Supports very large files since it downloads data in chunks.
/// </summary>
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请检查

  • 感谢您对[FluentFTP](https://github.com/robinrodricks/FluentFTP)的建议,与具有更多功能的内置`FtpWebRequest`相比,它看起来更容易使用.最终的原因是防火墙问题,但你也可以争辩说,使用合适的库,它从来就不是一个问题.无论哪种方式,我相信这个答案最能解决这个问题.谢谢. (3认同)