Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

when upload big file(11g db backup file), timed out trying to read data from the socket stream! #387

Closed
luchunminglu opened this issue Mar 27, 2019 · 34 comments

Comments

@luchunminglu
Copy link

luchunminglu commented Mar 27, 2019

**FTP OS: winserver2016

**FTP Server:filezilla0.9.60

**Computer OS:winserver 2012

it doesn't happen when upload small file.
when upload a big(test on 200mb & 10gb) db backup file, client.UploadFile(localFullFilePath, ftpFullPath) method report a timeout exception.The Error is "Timed out trying to read data from the socket stream! "
the wield thing is the db file is actual uploaded, i check the file size in ftp is right(but not check the file content).
so i think may be after upload big file, the flutent ftp does something read, which cause this error.

FluentFTP.FtpException: Error while uploading the file to the server. See InnerException for more info. ---> System.TimeoutException: Timed out trying to read data from the socket stream!
在 FluentFTP.FtpSocketStream.Read(Byte[] buffer, Int32 offset, Int32 count)
在 FluentFTP.FtpSocketStream.ReadLine(Encoding encoding)
在 FluentFTP.FtpClient.GetReply()
在 FluentFTP.FtpClient.UploadFileInternal(Stream fileData, String remotePath, Boolean createRemoteDir, FtpExists existsMode, Boolean fileExists, Boolean fileExistsKnown, IProgress1 progress) --- 内部异常堆栈跟踪的结尾 --- 在 FluentFTP.FtpClient.UploadFileInternal(Stream fileData, String remotePath, Boolean createRemoteDir, FtpExists existsMode, Boolean fileExists, Boolean fileExistsKnown, IProgress1 progress)
在 FluentFTP.FtpClient.UploadFileFromFile(String localPath, String remotePath, Boolean createRemoteDir, FtpExists existsMode, Boolean fileExists, Boolean fileExistsKnown, FtpVerify verifyOptions, IProgress1 progress) 在 FluentFTP.FtpClient.UploadFile(String localPath, String remotePath, FtpExists existsMode, Boolean createRemoteDir, FtpVerify verifyOptions, IProgress1 progress)

(000001)2019/3/28 12:50:03 - scims (192.168.163.1)> OPTS UTF8 ON
(000001)2019/3/28 12:50:03 - scims (192.168.163.1)> 202 UTF8 mode is always enabled. No need to send this command.
(000001)2019/3/28 12:50:03 - scims (192.168.163.1)> SYST
(000001)2019/3/28 12:50:03 - scims (192.168.163.1)> 215 UNIX emulated by FileZilla
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> PWD
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> 257 "/" is current directory.
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> SIZE /r2012.jpg
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> 550 File not found
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> TYPE I
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> 200 Type set to I
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> EPSV
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> 229 Entering Extended Passive Mode (|||61165|)
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> STOR r2012.jpg
(000001)2019/3/28 12:50:07 - scims (192.168.163.1)> 150 Opening data channel for file upload to server of "/r2012.jpg"
(000001)2019/3/28 12:54:48 - scims (192.168.163.1)> disconnected.
(000001)2019/3/28 12:54:48 - scims (192.168.163.1)> 226 Successfully transferred "/r2012.jpg"
(000001)2019/3/28 12:54:48 - scims (192.168.163.1)> could not send reply, disconnected.

@stefanolazzarato
Copy link

**FTP Server: Synology NAS (DSM 6.2.1-23824 Update 6)
**Computer OS: WinServer 2016 DataCenter
**FluentFTP version: 23.1.0

**Filesize: 730MB

I have the same problem. The upload is completed correctly and the file is valid.
When the upload is complete, a timeout time is expected, then returns the error.

@robinrodricks
Copy link
Owner

Try this and tell me if it works:

DataConnectionType = FtpDataConnectionType.EPSV

@luchunminglu
Copy link
Author

change to DataConnectionType = FtpDataConnectionType.EPSV, still same problem

@nicojmb
Copy link

nicojmb commented May 2, 2019

**FTP Server: Filezilla Server on Windows Server 2016
**Computer OS: WinServer 2019 DataCenter (on Azure)
**FluentFTP version: 24.0.0.0

**Filesize: 17GB

I have the same problem. The upload is completed correctly and the file is valid but thrown an exception:

Timed out trying to read data from the socket stream!

@icnocop
Copy link

icnocop commented May 11, 2019

I migrated my code from System.Net.FtpWebRequest to FluentFTP, thinking it would solve this issue.
I get this error when downloading large files.
I took the suggestion from https://stackoverflow.com/a/48983508/90287.

I recommend trying client.SocketKeepAlive = true; to see if that resolves the issue.

Here are the code comments for DataConnectionType:

Data connection type, default is AutoPassive which tries a connection with EPSV first and if it fails then tries PASV before giving up. If you know exactly which kind of connection you need you can slightly increase performance by defining a specific type of passive or active data connection here.

The log in the original post indicated that the client connected using EPSV.

Someone indicated that updating their FileZilla server resolved the issue.

Thank you.

Edit
Setting client.SocketKeepAlive = true; did not resolve the issue.

I also tried setting client.ReadTimeout = -1; and client.ReadTimeout = Int32.MaxValue; but then the download method didn't return after the file was downloaded.

@wjchristenson2
Copy link

wjchristenson2 commented Aug 19, 2019

I'm having the exact same problem. File size I am trying to download is 4.3GB. After the file has been downloaded entirely, I get an exception: FluentFTP.FtpException: Error while downloading the file from the server. See InnerException for more info. ---> System.TimeoutException: Timed out trying to read data from the socket stream!

I tried doubling the ReadTimeout and DataConnectionReadTimeout initially before realizing the file was downloading entirely before the exception. Like @icnocop I migrated to FluentFTP from System.Net.FtpWebRequest thinking the issue would resolve but then found this thread. Anyone find any fixes to this?

Edit: I should note, I am able to download the file using FileZilla and CuteFTP without issue.

@stefanolazzarato
Copy link

stefanolazzarato commented Aug 20, 2019

I solved it this way...

int progress = -1;
try
{
   FtpClient client = new FtpClient("HOST");
   client.Credentials = new NetworkCredential("USER", "PASSWORD");
   client.Connect();

   client.UploadFile("LOCALPATH/FILENAME", "REMOTEPATH/FILENAME",
       FtpExists.Overwrite,
       false,
       FtpVerify.None,
       new Progress<FtpProgress>(p => progress = Convert.ToInt32(p.Progress))
       );
}
catch (Exception ex)
{
   if (progress == 100 && ex is FluentFTP.FtpException && ex.InnerException != null && ex.InnerException is TimeoutException)
   {
       // Upload complete
       // LOG Info exception
   }
   else
   {
       // LOG Fatal exception
       throw;
   }
}

@wjchristenson2
Copy link

The @stefanolazzarato has been working up until today. Downloaded an 11,525 KB file and got a System.OverflowException on converting the progress value to an Int32 in production. Haven't been able to debug it - did look at the FluentFTP ReportProgress function looks like it is doing a progressValue = (double) position / (double) fileSize * 100; Likely bad values are getting in - going to try to make the progress variable a double and check for >= 100 on exception instead.

@robinrodricks
Copy link
Owner

@stefanolazzarato thanks for this fix, I finally understood the problem! I've attempted to absorb all TimeoutExceptions during upload/download if the file is fully transferred in the latest version https://www.nuget.org/packages/FluentFTP/27.1.4

@stefanolazzarato @wjchristenson2 @icnocop @nicojmb @luchunminglu
Can everyone test the latest version and see if you are still getting those pesky errors?

@stefanolazzarato
Copy link

@robinrodricks I updated my project to the new version. I'll try it in the next days.

@icnocop
Copy link

icnocop commented Oct 31, 2019

Thank you, @robinrodricks.

I updated to FluentFTP 27.1.4 but I still get a TimeoutException when downloading a 3.43 GB file.

When the exception is thrown, progress is at 100%, so I'm able to use @stefanolazzarato's workaround.

Here's the stack trace:

FluentFTP.FtpException: Error while downloading the file from the server. See InnerException for more info. ---> System.TimeoutException: Timed out trying to read data from the socket stream!
   at FluentFTP.FtpSocketStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at FluentFTP.FtpSocketStream.ReadLine(Encoding encoding)
   at FluentFTP.FtpClient.GetReply()
   at FluentFTP.FtpClient.DownloadFileInternal(String remotePath, Stream outStream, Int64 restartPosition, IProgress`1 progress)
   --- End of inner exception stack trace ---
   at FluentFTP.FtpClient.DownloadFileInternal(String remotePath, Stream outStream, Int64 restartPosition, IProgress`1 progress)
   at FluentFTP.FtpClient.DownloadFileToFile(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, IProgress`1 progress)
   at FluentFTP.FtpClient.DownloadFile(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, IProgress`1 progress)

@robinrodricks
Copy link
Owner

@icnocop Please try the latest release, it should be fixed now..

https://www.nuget.org/packages/FluentFTP/28.0.1

@wenbingzhang
Copy link

Still exist

@SETSinsperion
Copy link

Greetings. Testing 28.0.1 at console app (package added via Nuget).

@SETSinsperion
Copy link

SETSinsperion commented Nov 16, 2019

Test finished:

  • File size: 1.9 GB (ubuntu .iso)
  • Port: 21
  • Action: Upload file

Sorry, the problem about TimeoutException still exists :( @robinrodricks

@icnocop
Copy link

icnocop commented Nov 16, 2019

@SETSinsperion, can you provide a stack trace?

@SETSinsperion
Copy link

@icnocop of course, but I'm sorry, I closed the project having in mind that your answer will be later. I will test again and I provide my stack trace..

@SETSinsperion
Copy link

SETSinsperion commented Nov 16, 2019

@icnocop @robinrodricks Test finished: I have a upload method inside a .dll created for me, the first StackTrace is the Main method which I call the upload method. The 2nd Stacktrace is the main interest:

StackTrace

1. In Main.cs
One or more errors occurred. (Error while uploading the file to the server. See InnerException for more info.)

at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) at System.Threading.Tasks.Task.Wait() at Aleiser_ECS_Gral_Function_Test.Program.Main(String[] args) in D:\Documents\Visual Studio 2019\Projects\Aleiser ECS Gral Function Test\Main.cs:line 39

2. This exception has an InnerException that is the StackTrace that throws upload method:
Timed out trying to read data from the socket stream! | System.Exception {System.TimeoutException}

at FluentFTP.FtpSocketStream.<ReadAsync>d__68.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at FluentFTP.FtpSocketStream.<ReadLineAsync>d__71.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at FluentFTP.FtpClient.<GetReplyAsync>d__179.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at FluentFTP.FtpClient.<UploadFileInternalAsync>d__153.MoveNext()

InnerException 1:
FtpException: Error while uploading the file to the server. See InnerException for more info.

InnerException 2:
TimeoutException: Timed out trying to read data from the socket stream!

Code:

Main.cs

        static void Main(string[] args)
        {
            UploadTaskFTP u = new UploadTaskFTP(Server, User, Pass);
            // SetGUIProgressUpdatesFTP() is returning an Progress object, to report in the console the upload percent
            u.FtpUploadFileAsync(@"D:\Downloads\ubuntu.iso", "/directory/to/upload", SetGUIProgressUpdatesFTP()).Wait();
        }

Upload method:

        public async Task FtpUploadFileAsync(string filePath, string dirTo, IProgress<FtpProgress> progress)
        {
            FtpClient client = new FtpClient(Server);
            this.progress = progress;
            string remoteFilePath = string.Format(
                "{0}/{1}", dirTo, (filePath.Split(Path.DirectorySeparatorChar).Reverse()).ElementAt(0));

            try
            {
                if (File.Exists(filePath))
                {
                    client.Credentials = new NetworkCredential(User, Pass);
                    await client.ConnectAsync();

                    if (await client.DirectoryExistsAsync(dirTo))
                    {
                        await client.UploadFileAsync(filePath, remoteFilePath, progress: progress);
                    }
                    else
                    {
                        throw new Exception($"Directory {dirTo} doesn't exist. Please try another to upload.");
                    }
                }
                else
                {
                    throw new FileNotFoundException($"File {filePath} doesn't exist or is used by another process.");
                }
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                if (client.IsConnected)
                    await client.DisconnectAsync();
            }
        }

I hope this will guide to a solution.

@icnocop
Copy link

icnocop commented Nov 26, 2019

Hi.

I updated to FluentFTP 28.0.2 from NuGet.

I downloaded a 3.46 GB file, but still received the same exception:

FluentFTP.FtpException: Error while downloading the file from the server. See InnerException for more info. ---> System.TimeoutException: Timed out trying to read data from the socket stream!
   at FluentFTP.FtpSocketStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at FluentFTP.FtpSocketStream.ReadLine(Encoding encoding)
   at FluentFTP.FtpClient.GetReply()
   at FluentFTP.FtpClient.DownloadFileInternal(String remotePath, Stream outStream, Int64 restartPosition, Action`1 progress)
   --- End of inner exception stack trace ---
   at FluentFTP.FtpClient.DownloadFileInternal(String remotePath, Stream outStream, Int64 restartPosition, Action`1 progress)
   at FluentFTP.FtpClient.DownloadFileToFile(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, Action`1 progress)
   at FluentFTP.FtpClient.DownloadFile(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, Action`1 progress)

Thank you.

@andrejlucansky
Copy link

andrejlucansky commented Dec 11, 2019

Hi,

I am using version 28.0.5.

Same timeout exception still occurs when downloading. In my case, file size is approximately 400MB. Sometimes the download times out at 99%, sometimes at 100%. Download gets to 99% hangs for the duration of timeout (15 sec in this case - default timeout) and throws TimeoutException.

I find his quite interesting, because I actually started using FluentFTP to get rid of this exact problem. At first, I wrote a basic downloader using WebClient and it experienced very similar behavior. File download got to 99% or 100% and then stopped, doing nothing, until it eventually timed out. I was not able to fix it, so I worked around it by using Polly and just re-tried the download request when timeout expired. I recently heard about FluentFTP and I thought it might be able to fix the issue, so I gave it a shot, but with the same results. Code and logs below:

My code:

client.OnLogEvent = OnFtpLogEvent;
client.RetryAttempts = 5;
client.DataConnectionType = FtpDataConnectionType.EPSV;

try
{
    await client.ConnectAsync(cancellationToken);
    await client.DownloadFileAsync(Destination, Source.LocalPath, FtpLocalExists.Append, FtpVerify.Retry, ProgressCallback(), cancellationToken);
}
catch (FtpException exception)
{
    File.Delete(Destination);
    return;
}
finally
{
    await client.DisconnectAsync(cancellationToken);
}

Logs:

2019-12-11 11:59:00.266 +08:00 [Debug] Downloaded: 95%, ETA: 17 seconds, Speed: 1.02 MB/s
2019-12-11 11:59:01.973 +08:00 [Debug] Downloaded: 96%, ETA: 13 seconds, Speed: 1.02 MB/s
2019-12-11 11:59:03.423 +08:00 [Debug] Downloaded: 97%, ETA: 9 seconds, Speed: 1.03 MB/s
2019-12-11 11:59:13.212 +08:00 [Debug] Downloaded: 98%, ETA: 6 seconds, Speed: 1.01 MB/s
2019-12-11 11:59:19.516 +08:00 [Debug] Downloaded: 99%, ETA: 2 seconds, Speed: 1.01 MB/s
2019-12-11 11:59:35.910 +08:00 [Error] FTP/S download request failed at 99%:
FluentFTP.FtpException: Error while downloading the file from the server. See InnerException for more info.
 ---> System.TimeoutException: Timed out trying to read data from the socket stream!
   at FluentFTP.FtpSocketStream.ReadAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken token)
   at FluentFTP.FtpSocketStream.ReadLineAsync(Encoding encoding, CancellationToken token)
   at FluentFTP.FtpClient.GetReplyAsync(CancellationToken token)
   at FluentFTP.FtpClient.DownloadFileInternalAsync(String remotePath, Stream outStream, Int64 restartPosition, IProgress`1 progress, CancellationToken token)
   --- End of inner exception stack trace ---
   at FluentFTP.FtpClient.DownloadFileInternalAsync(String remotePath, Stream outStream, Int64 restartPosition, IProgress`1 progress, CancellationToken token)
   at FluentFTP.FtpClient.DownloadFileToFileAsync(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, IProgress`1 progress, CancellationToken token)
   at FluentFTP.FtpClient.DownloadFileAsync(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, IProgress`1 progress, CancellationToken token)
   at FtpDownloader.DownloadAsync(CancellationToken cancellationToken) in \Downloader\FtpDownloader.cs:line 59
2019-12-11 11:59:35.924 +08:00 [Information] Download finished after 385.560881 seconds

I hope this will get fixed soon, but in the meantime I went back to retrying via Polly. Maybe someone'll find this useful as a temporary workaround:

using (var client = new FtpClient(Source.Host))
{
    AsyncRetryPolicy policy = Policy.Handle<FtpException>().WaitAndRetryAsync(YourRetrySettings);
            
    try
    {
        await client.ConnectAsync(cancellationToken);
        await policy.ExecuteAsync(async ct => { 
            await client.DownloadFileAsync(Destination, Source.LocalPath, FtpLocalExists.Append, FtpVerify.Retry, YourProgressCallback, ct); 
        }, cancellationToken);
    }
    catch (FtpException exception)
    {
        // Error handling here
    }
    finally
    {
        await client.DisconnectAsync(cancellationToken);
    }
}

FtpClient is configured to append to an existing file (FtpLocalExists.Append). After Polly executes a retry, second call to server will detect that the file on the disk is the same size as the one on the server (even though the ProgressCallback got stuck at 99%). This will result in a graceful termination and the download will finish:

2019-12-11 13:16:35.864 +00:00 [Debug] Status:   Connecting to ***
...
2019-12-11 13:16:40.624 +00:00 [Debug] Status:   Append is enabled => Local file size matches size on server => skipping
2019-12-11 13:16:40.627 +00:00 [Debug] Command:  QUIT
2019-12-11 13:16:40.837 +00:00 [Debug] Response: 221 Goodbye.

@aliquid
Copy link

aliquid commented Jan 4, 2020

Experiencing same problem with v28.0.5 when uploading files larger than ~460,000,000 bytes (or that takes longer than ~280), hangs on completion throwing TimeoutException. FluentFTP client runs in Azure VM, server runs IIS outside of Azure. Reproduces every time. Details below.

Successfully working around by setting EnableThreadSafeDataConnections = true.

The if (!EnableThreadSafeDataConnections) { var status = GetReply(); ... in FtpClient_HighLevelUpload.cs led me to the workaround. I don't know the details of the FTP protocol but that code is rogue - if thread-safe then ignore error, if not then wait for response, which in the error-case does not come.

  • Timeout?
  • Should not the while-loop that uploads the file in UploadFileInternal/Async() do some polling with respect to SocketPollInterval to prevent that? @robinrodricks
            using (var client = new FluentFTP.FtpClient()
            {
                Host = host,
                Port = port,
                Credentials = new NetworkCredential(username, password),
                //
                ConnectTimeout = 3000, // tried 3..120s
                ReadTimeout = 3000, // tried 3..120s
                DataConnectionConnectTimeout = 3000, // tried 3..120s
                DataConnectionReadTimeout = 3000, // tried 3..120s
                DataConnectionType = FtpDataConnectionType.AutoPassive,
                SocketKeepAlive = true,
                SocketPollInterval = 1000, // makes no difference
                EnableThreadSafeDataConnections = false // true works around the problem
            })
            using (var stream = File.OpenRead(file))
            {
                Console.Write("Connecting...");
                client.Connect();

                Console.Write("Changing directory...");
                client.SetWorkingDirectory(path);

                Console.Write("Uploading...");
                client.Upload(stream, Path.GetFileName(file));
 
                Console.Write("Disconnecting...");
                client.Disconnect();
            }

Running client in AzureVM, throws after ~290 seconds when upload has completed;

...
# DeleteFile("IgnoreMe.tmp")
Command:  DELE IgnoreMe.tmp
Response: 250 DELE command successful.

# OpenWrite("IgnoreMe.tmp", Binary)
Command:  TYPE I
Response: 200 Type set to I.

# OpenPassiveDataStream(AutoPassive, "STOR IgnoreMe.tmp", 0)
Command:  EPSV
Response: 500 'EPSV': command not understood

# OpenPassiveDataStream(PASV, "STOR IgnoreMe.tmp", 0)
Command:  PASV
Response: 227 Entering Passive Mode (...).
Status:   Connecting to ...
Command:  STOR IgnoreMe.tmp
Response: 125 Data connection already open; Transfer starting.
Status:   Disposing FtpSocketStream...
Status:   Testing connectivity using Socket.Poll()...
Status:   Disposing FtpSocketStream...
Status:   Disposing FtpSocketStream...

Unhandled Exception: FluentFTP.FtpException: Error while uploading the file to the server. See InnerException for more info. ---> System.TimeoutException: Timed out trying to read data from the socket stream!
   at FluentFTP.FtpSocketStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at FluentFTP.FtpSocketStream.ReadLine(Encoding encoding)
   at FluentFTP.FtpClient.GetReply()
   at FluentFTP.FtpClient.UploadFileInternal(Stream fileData, String remotePath, Boolean createRemoteDir, FtpExists existsMode, Boolean fileExists, Boolean fileExistsKnown, Action`1 progress)
   --- End of inner exception stack trace ---
   at FluentFTP.FtpClient.UploadFileInternal(Stream fileData, String remotePath, Boolean createRemoteDir, FtpExists existsMode, Boolean fileExists, Boolean fileExistsKnown, Action`1 progress)
   at FluentFTP.FtpClient.Upload(Stream fileStream, String remotePath, FtpExists existsMode, Boolean createRemoteDir, Action`1 progress)
   at ftplab.Program.Main(String[] args)

On my laptop instead of Azure VM the client upload successfully runs in 100 seconds instead of 290 seconds;

...
# OpenPassiveDataStream(PASV, "STOR IgnoreMe.tmp", 0)
Command:  PASV
Response: 227 Entering Passive Mode (...).
Status:   Connecting to ...
Command:  STOR IgnoreMe.tmp
Response: 125 Data connection already open; Transfer starting.
Status:   Disposing FtpSocketStream...
Status:   Testing connectivity using Socket.Poll()...
Response: 226 Transfer complete.
Disconnecting...Command:  QUIT
Response: 221
Status:   Disposing FtpSocketStream...

# Dispose()
Status:   Disposing FtpClient object...
Status:   Disposing FtpSocketStream...
Done in 104663 milliseconds

Finally running in AzureVM with workaround, GetReply() times out but exception is discarded.

# OpenPassiveDataStream(PASV, "STOR IgnoreMe.tmp", 0)
Command:  PASV
Response: 227 Entering Passive Mode (...).
Status:   Connecting to ...
Command:  STOR IgnoreMe.tmp
Response: 125 Data connection already open; Transfer starting.
Status:   Disposing FtpSocketStream...
Disconnecting...Status:   Testing connectivity using Socket.Poll()...
Command:  QUIT
Status:   Disposing FtpSocketStream...
Warning:  FtpClient.Disconnect(): Exception caught and discarded while closing control connection: System.TimeoutException: Timed out trying to read data from the socket stream!
   at FluentFTP.FtpSocketStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at FluentFTP.FtpSocketStream.ReadLine(Encoding encoding)
   at FluentFTP.FtpClient.GetReply()
   at FluentFTP.FtpClient.Execute(String command)
   at FluentFTP.FtpClient.Disconnect()
Status:   Disposing FtpSocketStream...

# Dispose()
Status:   Disposing FtpClient object...
Status:   Disposing FtpSocketStream...
Done in 275222 milliseconds

# Dispose()
Status:   Disposing FtpClient object...
Status:   Testing connectivity using Socket.Poll()...
Command:  QUIT
Warning:  FtpClient.Disconnect(): Exception caught and discarded while closing control connection: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.
   at System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   at FluentFTP.FtpSocketStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at FluentFTP.FtpSocketStream.WriteLine(Encoding encoding, String buf)
   at FluentFTP.FtpClient.Execute(String command)
   at FluentFTP.FtpClient.Disconnect()
Status:   Disposing FtpSocketStream...
Status:   Disposing FtpSocketStream...

aliquid pushed a commit to aliquid/FluentFTP that referenced this issue Jan 4, 2020
@aliquid
Copy link

aliquid commented Jan 4, 2020

@robinrodricks created a pull request tested successfully with uploading large file

There are opinions about sending NOOP during file transfer, but bottom-line is that it solves these types of problems;

Please note that I fired the code for downloading from the hip, just more of the same as for uploading that I have verified (trace below).

            using (var client = new FluentFTP.FtpClient()
            {
                Host = host,
                Port = port,
                Credentials = new NetworkCredential(username, password),
                //
                ConnectTimeout = 3000,
                ReadTimeout = 3000,
                DataConnectionConnectTimeout = 3000,
                DataConnectionReadTimeout = 3000,
                DataConnectionType = FtpDataConnectionType.AutoPassive,
                SocketKeepAlive = true,
                SocketPollInterval = 15000,
                EnableThreadSafeDataConnections = false,
                NoopInterval = 15000, //<<<<<<<<<<<<<<<<<<<<<<<< Send NOOP every 15 seconds
            })
            using (var stream = File.OpenRead(file))
            {
                Console.Write("Connecting...");
                client.Connect();

                Console.Write("Changing directory...");
                client.SetWorkingDirectory(path);

                Console.Write("Uploading...");
                client.Upload(stream, Path.GetFileName(file));
 
                Console.Write("Disconnecting...");
                client.Disconnect();
            }
Connecting...
# Connect()
Status:   Connecting to ***:21
Response: 220 Microsoft FTP Service
Status:   Detected FTP server: WindowsServerIIS
Command:  USER ***
Response: 331 Password required for ***.
Command:  PASS ***
Response: 230 User *** logged in.
Command:  FEAT
Response: 211-FEAT
Response: SIZE
Response: MDTM
Response: 211 END
Status:   Text encoding: System.Text.ASCIIEncoding
Command:  SYST
Response: 215 Windows_NT
Changing directory...
# SetWorkingDirectory("/***")
Command:  CWD /***
Response: 250 CWD command successful.
Uploading...
# Upload("IgnoreMe.tmp", Overwrite, False)

# FileExists("IgnoreMe.tmp")

# GetWorkingDirectory()
Command:  PWD
Response: 257 "/***" is current directory.
Command:  SIZE /***/IgnoreMe.tmp
Response: 213 486389347

# DeleteFile("IgnoreMe.tmp")
Command:  DELE IgnoreMe.tmp
Response: 250 DELE command successful.

# OpenWrite("IgnoreMe.tmp", Binary)
Command:  TYPE I
Response: 200 Type set to I.

# OpenPassiveDataStream(AutoPassive, "STOR IgnoreMe.tmp", 0)
Command:  EPSV
Response: 500 'EPSV': command not understood

# OpenPassiveDataStream(PASV, "STOR IgnoreMe.tmp", 0)
Command:  PASV
Response: 227 Entering Passive Mode (***).
Status:   Connecting to ***
Command:  STOR IgnoreMe.tmp
Response: 125 Data connection already open; Transfer starting.
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   NOOP keep-alive
Status:   Disposing FtpSocketStream...
Response: 226 Transfer complete.
Disconnecting...Command:  QUIT
Response: 221
Status:   Disposing FtpSocketStream...

# Dispose()
Status:   Disposing FtpClient object...
Status:   Disposing FtpSocketStream...
Done in 270603 milliseconds

Edit; fixed the logging so it says Command: NOOP properly

@aliquid
Copy link

aliquid commented Jan 5, 2020

Tested successfully also the Download operation;

            using (var client = new FluentFTP.FtpClient()
            {
                Host = host,
                Port = port,
                Credentials = new NetworkCredential(username, password),
                //
                ConnectTimeout = 3000,
                ReadTimeout = 3000,
                DataConnectionConnectTimeout = 3000,
                DataConnectionReadTimeout = 3000,
                DataConnectionType = FtpDataConnectionType.AutoPassive,
                SocketKeepAlive = true,
                SocketPollInterval = 15000,
                EnableThreadSafeDataConnections = false,
                NoopInterval = 15000,
            })
            using (var stream = File.OpenWrite(file))
            {
                Console.Write("Connecting...");
                client.Connect();

                Console.Write("Downloading...");
                client.Download(stream, path);

                Console.Write("Disconnecting...");
                client.Disconnect();
            }
Connecting...
# Connect()
Status:   Connecting to ***:21
Response: 220 Microsoft FTP Service
Status:   Detected FTP server: WindowsServerIIS
Command:  USER ***
Response: 331 Password required for ***.
Command:  PASS ***
Response: 230 User *** logged in.
Command:  FEAT
Response: 211-FEAT
Response: SIZE
Response: MDTM
Response: 211 END
Status:   Text encoding: System.Text.ASCIIEncoding
Command:  SYST
Response: 215 Windows_NT
Downloading...
# Download("/***/IgnoreMe.tmp")

# OpenRead("/***/IgnoreMe.tmp", Binary, 0)
Command:  TYPE I
Response: 200 Type set to I.

# OpenPassiveDataStream(AutoPassive, "RETR /***/IgnoreMe.tmp", 0)
Command:  EPSV
Response: 500 'EPSV': command not understood

# OpenPassiveDataStream(PASV, "RETR /***/IgnoreMe.tmp", 0)
Command:  PASV
Response: 227 Entering Passive Mode (***).
Status:   Connecting to ***:1667
Command:  RETR /***/IgnoreMe.tmp
Response: 125 Data connection already open; Transfer starting.
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Status:   Disposing FtpSocketStream...
Response: 226 Transfer complete.
Disconnecting...Command:  QUIT
Response: 221
Status:   Disposing FtpSocketStream...

# Dispose()
Status:   Disposing FtpClient object...
Status:   Disposing FtpSocketStream...
Done in 139894 milliseconds

@robinrodricks
Copy link
Owner

robinrodricks commented Jan 6, 2020

Thanks a ton @aliquid for fixing this long standing issue. Gone live with 29.0.0.

@luchunminglu @SETSinsperion @icnocop @stefanolazzarato @wjchristenson2 All are suggested to grab the latest version and see if it solves their problem:

https://www.nuget.org/packages/FluentFTP/29.0.0

If you still see errors, decrease the NoopInterval value and try again. Ensure its more than 5000 though as values lower than that would not have any benefit.

@aliquid
Copy link

aliquid commented Jan 6, 2020

Thnx @robinrodricks !! Successfully tested Upload and Download operations with 29.0.0 from our AzureVM environment, transferring 486MB file 290s up 110s down.

We integrate with a large number of completely different FTP servers, all behaving differently, so the configurable nature of FluentFTP is what makes it so great for us. For years we have been sending files a couple of KB up to 200 MB, but recently we started sending some odd files close to 300 MB to one of our endponts when problems started for us.

It seems that the AzureVM router or firewall does not respect TCP Keep-Alive on the control socket (port 21). When large file transfers runs on data socket (20 or passive) there is no traffic on the control socket and it breaks for us after ~280s (perhaps 240s). Before mentioned workaround setting EnableThreadSafeDataConnections = true simply caused the exception from the broken connection to be discarded, pretending all was fine and opening a new control socket.

The NOOP command responds something like '200 NOOP command successful.' and is typically used by a FTP UI client to keep the control socket alive in-between commands, so it is a good candidate for using also during long-running command executios (i.e. RETR/STOR). However the https://tools.ietf.org/html/rfc959 neither suggests that nor against it.

Indeed, googling shows that it has been proven in battle, with some odd complaints (see link to smartftp.com some comments back) that it could potentially cause file transfers to abort (remains to be proven) or make FTP servers behave strangely like not responding 200 (that is what I can see from IIS) or respond at the end of the file transfer (have no such evidence, but pull request attempted to cope with that in a rudimentary manner).

Suggested usage for NoopInterval (in milliseconds) from our experience;

  • 0 (default) if you can get away with it do not fiddle with it, keeping in mind that sending commands during command execution might not be by the book for all FTP server implementations out there
  • firewall timeout divided by 2, if you can determine the timeout by transferring files 10MB, 50MB, 100MB, 500MB, 1GB, 5GB
  • 30000 or 45000 or 90000 (corresponding to 30s, 45s or 90s) would make sense
  • not something like 1000 or 5000, that would be nonsensical because any socket must survive 5s silence, problem should be sought elsewhere like in the firewall

@aliquid
Copy link

aliquid commented Jan 6, 2020

... or respond at the end of the file transfer (have no such evidence, but pull request attempted to cope with that in a rudimentary manner).

Writing above got me thinking, adding below to just before the break in Upload/DownloadFileInternal/Async would make coping with NOOP responses less rudimentary and more robust by exhausting them not only before the "226 Transfer complete." but also after it (as should be the case, as specified by "4.2 FTP REPLIES" in the RFC 959). Of course Execute() can do that (if StaleDataCheck = true) with its ReadStaleData(true, ..), but with the side-effect of dropping the connection and opening a new.

This is theory as I have no evidence for it. I cannot experiment with all our endpoints to see if any would be responding at all to NOOPs during file transfers, only with our internal which runs IIS. Perhaps others reading could help provide evidence one way or the other by uploading/downloading two files consequtively with NoopInterval configured to see if it triggers with StaleDataCheck = true? I tested multiple consecutive uploads and downloads but with IIS there are no NOOP responses during file transfer so existing code stands file.

Just wanted to get this concern off my chest.

				while (!m_threadSafeDataChannels) {
... existing code up to here stands fine imo ...

					// Fix #387: exhaust any NOOP responses also after "226 Transfer complete."
					if (anyNoop)
						ReadStaleData(false, true, true); // await ReadStaleDataAsync(..., token);
					break;
				}

@robinrodricks
Copy link
Owner

robinrodricks commented Jan 6, 2020 via email

aliquid pushed a commit to aliquid/FluentFTP that referenced this issue Jan 6, 2020
@aliquid
Copy link

aliquid commented Jan 6, 2020

No problem. Below from my testing but again it shows no evidence the added code does anything.

Uploading, with IIS no sign of stale data after 226 Transfer complete.;

Connecting...
# Connect()
Status:   Connecting to ***:21
Response: 220 Microsoft FTP Service
Status:   Detected FTP server: WindowsServerIIS
Command:  USER ***
Response: 331 Password required for ***.
Command:  PASS ***
Response: 230 User *** logged in.
Command:  FEAT
Response: 211-FEAT
Response: SIZE
Response: MDTM
Response: 211 END
Status:   Text encoding: System.Text.ASCIIEncoding
Command:  SYST
Response: 215 Windows_NT
Changing directory...
# SetWorkingDirectory("/***/temp")
Command:  CWD /***/temp
Response: 250 CWD command successful.
Uploading...
# Upload("IgnoreMe1.tmp", Overwrite, False)

# FileExists("IgnoreMe1.tmp")

# GetWorkingDirectory()
Command:  PWD
Response: 257 "/***/temp" is current directory.
Command:  SIZE /***/temp/IgnoreMe1.tmp
Response: 213 75869544

# DeleteFile("IgnoreMe1.tmp")
Command:  DELE IgnoreMe1.tmp
Response: 250 DELE command successful.

# OpenWrite("IgnoreMe1.tmp", Binary)
Command:  TYPE I
Response: 200 Type set to I.

# OpenPassiveDataStream(AutoPassive, "STOR IgnoreMe1.tmp", 0)
Command:  EPSV
Response: 500 'EPSV': command not understood

# OpenPassiveDataStream(PASV, "STOR IgnoreMe1.tmp", 0)
Command:  PASV
Response: 227 Entering Passive Mode (***).
Status:   Connecting to ***:2966
Command:  STOR IgnoreMe1.tmp
Response: 125 Data connection already open; Transfer starting.
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Status:   Disposing FtpSocketStream...
Response: 226 Transfer complete.
Uploading...
# Upload("IgnoreMe1.tmp", Overwrite, False)

# FileExists("IgnoreMe1.tmp")

# GetWorkingDirectory()
Command:  PWD
Response: 257 "/***/temp" is current directory.
Command:  SIZE /***/temp/IgnoreMe1.tmp
Response: 213 75869544

# DeleteFile("IgnoreMe1.tmp")
Command:  DELE IgnoreMe1.tmp
Response: 250 DELE command successful.

# OpenWrite("IgnoreMe1.tmp", Binary)

# OpenPassiveDataStream(AutoPassive, "STOR IgnoreMe1.tmp", 0)
Command:  PASV
Response: 227 Entering Passive Mode (***).
Status:   Connecting to ***:3217
Command:  STOR IgnoreMe1.tmp
Response: 125 Data connection already open; Transfer starting.
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Status:   Disposing FtpSocketStream...
Response: 226 Transfer complete.
Disconnecting...Command:  QUIT
Response: 221
Status:   Disposing FtpSocketStream...

# Dispose()
Status:   Disposing FtpClient object...
Status:   Disposing FtpSocketStream...
Done in 86241 milliseconds

Downloading, with IIS no sign of stale data after 226 Transfer complete.;

Connecting...
# Connect()
Status:   Connecting to ***:21
Response: 220 Microsoft FTP Service
Status:   Detected FTP server: WindowsServerIIS
Command:  USER ***
Response: 331 Password required for ***.
Command:  PASS ***
Response: 230 User *** logged in.
Command:  FEAT
Response: 211-FEAT
Response: SIZE
Response: MDTM
Response: 211 END
Status:   Text encoding: System.Text.ASCIIEncoding
Command:  SYST
Response: 215 Windows_NT
Downloading...
# Download("/***/temp/IgnoreMe1.tmp")

# OpenRead("/***/temp/IgnoreMe1.tmp", Binary, 0)
Command:  TYPE I
Response: 200 Type set to I.

# OpenPassiveDataStream(AutoPassive, "RETR /***/temp/IgnoreMe1.tmp", 0)
Command:  EPSV
Response: 500 'EPSV': command not understood

# OpenPassiveDataStream(PASV, "RETR /***/temp/IgnoreMe1.tmp", 0)
Command:  PASV
Response: 227 Entering Passive Mode (***).
Status:   Connecting to ***:3423
Command:  RETR /***/temp/IgnoreMe1.tmp
Response: 125 Data connection already open; Transfer starting.
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Status:   Disposing FtpSocketStream...
Response: 226 Transfer complete.
Downloading...
# Download("/***/temp/IgnoreMe1.tmp")

# OpenRead("/***/temp/IgnoreMe1.tmp", Binary, 0)

# OpenPassiveDataStream(AutoPassive, "RETR /***/temp/IgnoreMe1.tmp", 0)
Command:  PASV
Response: 227 Entering Passive Mode (***).
Status:   Connecting to ***:3504
Command:  RETR /***/temp/IgnoreMe1.tmp
Response: 125 Data connection already open; Transfer starting.
Command:  NOOP
Command:  NOOP
Command:  NOOP
Command:  NOOP
Status:   Disposing FtpSocketStream...
Response: 226 Transfer complete.
Disconnecting...Command:  QUIT
Response: 221
Status:   Disposing FtpSocketStream...

# Dispose()
Status:   Disposing FtpClient object...
Status:   Disposing FtpSocketStream...
Done in 42913 milliseconds

@icnocop
Copy link

icnocop commented Jan 17, 2020

Unfortunately I'm getting an exception when trying to download a large file using FluentFTP 29.0.1 with these settings:

client.SocketKeepAlive = true;
client.SocketPollInterval = 15000;
client.EnableThreadSafeDataConnections = false;
client.NoopInterval = 15000;

Exception:

FluentFTP.FtpException: Error while downloading the file from the server. See InnerException for more info. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at FluentFTP.FtpExtensions.IsKnownError(String reply, String[] strings)
   at FluentFTP.FtpClient.GetFileSizeInternal(String path, FtpSizeReply sizeReply)
   at FluentFTP.FtpClient.GetFileSize(String path)
   at FluentFTP.FtpClient.OpenRead(String path, FtpDataType type, Int64 restart, Boolean checkIfFileExists)
   at FluentFTP.FtpClient.OpenRead(String path, FtpDataType type, Int64 restart)
   at FluentFTP.FtpClient.ResumeDownload(String remotePath, Stream& downStream, Int64 offset, IOException ex)
   at FluentFTP.FtpClient.DownloadFileInternal(String remotePath, Stream outStream, Int64 restartPosition, Action`1 progress)
 --- End of inner exception stack trace ---
   at FluentFTP.FtpClient.DownloadFileInternal(String remotePath, Stream outStream, Int64 restartPosition, Action`1 progress)
   at FluentFTP.FtpClient.DownloadFileToFile(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, Action`1 progress)
   at FluentFTP.FtpClient.DownloadFile(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, Action`1 progress)

The file is about 3.5 GB.
The exception occurs after about 8 minutes.
At the time of the exception, the progress of the download is about 15%.

Any ideas?

Thank you.

@robinrodricks
Copy link
Owner

robinrodricks commented Jan 17, 2020 via email

@icnocop
Copy link

icnocop commented Jan 17, 2020

Thank you.

Unfortunately I'm still getting the TimeoutException when downloading a large file using FluentFTP 29.0.1 with these settings:

client.SocketKeepAlive = true;
client.SocketPollInterval = 15000;
client.EnableThreadSafeDataConnections = false;
FluentFTP.FtpException: Error while downloading the file from the server. See InnerException for more info. ---> System.TimeoutException: Timed out trying to read data from the socket stream!
   at FluentFTP.FtpSocketStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at FluentFTP.FtpSocketStream.ReadLine(Encoding encoding)
   at FluentFTP.FtpClient.GetReply()
   at FluentFTP.FtpClient.DownloadFileInternal(String remotePath, Stream outStream, Int64 restartPosition, Action`1 progress)
   --- End of inner exception stack trace ---
   at FluentFTP.FtpClient.DownloadFileInternal(String remotePath, Stream outStream, Int64 restartPosition, Action`1 progress)
   at FluentFTP.FtpClient.DownloadFileToFile(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, Action`1 progress)
   at FluentFTP.FtpClient.DownloadFile(String localPath, String remotePath, FtpLocalExists existsMode, FtpVerify verifyOptions, Action`1 progress)

At the time of the exception, the progress of the download is 100%.

@robinrodricks
Copy link
Owner

@icnocop Check this:

https://www.nuget.org/packages/FluentFTP/29.0.3

@icnocop
Copy link

icnocop commented Jan 25, 2020

@robinrodricks, that worked! 🎉

FluentFTP 29.0.3 no longer throws a TimeoutException when downloading a large file (3.53 GB).

Thank you very much! 😃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants