I use a TIdFTP control to connect to an FTP server. It seems that my FTP connection is terminated by something (ftp server/firewall?) after 60 seconds of inactivity. Once the connection was terminated I cannot use the FTP control (TIdFTP) anymore because its status is undefined. For example, every time I try to REconnect I get the same (10038) error. However, FTP.Connected shows True. Trying FTP.Disconnect gives me a 'connection closed gracefully' error and the control remains connected. The only solution is to end the program and start it again.
The NAT Keep Alive is already set to 15000.
How to reset the status of the FTP control (how do I disconnect)?
I use a TIdFTP control to connect to an FTP server. It seems that my FTP connection is terminated by something (ftp server/firewall?) after 60 seconds of inactivity
TIdFTP has a NATKeepAlive property to avoid that exact issue from happening when connected through an FTP-unaware router/firewall. During a transfer, TCP keepalives are temporarily enabled on the control connection so it does not get closed prematurely.
However, FTP.Connected shows True.
That means the IOHandler.InputBuffer likely has unread data in it. Connected() is designed to return True if read operations can still be satisfied even if the socket has been closed.
Trying FTP.Disconnect gives me a 'connection closed gracefully' error
By default, Disconnect() sends a QUIT command to the server before closing the socket. Since the connection is already gone, that send fails.
Disconnect() has an optional ANotifyPeer parameter that you can set to False to skip the QUIT command.
You should also Clear() the IOHandler.InputBuffer after an unexpected disconnect to clear out any unread data.
The only solution is to end the program and start it again.
That is never the solution. Worse case, you could simply destroy the TIdFTP object and create a new one. But if you follow the steps above, you should not need to resort to even that.
You cannot keep TIdFTP open. The connection will be closed from server side for every timed out time.
As you use this component to fetch or put file to file server for a time interval, You can connect just before using the TIDFTP, and disconnect it after the usage. Then you do not need to bother about freeing the component and connection failures.
Related
I tested a simulation disconnect of multiple clients by cutting their internet connection. I found that TIdTCPServer did not discharge their threads, it did not detect their disconnect. By comparison, when I closed a client manually, the server detected the disconnection and discharged its thread.
Abnormal disconnects are not detected by the OS in a timely manner. It can take a considerable amount of time for a lost socket connection to timeout internally so the OS can invalidate it. Until the OS does that, Indy has no way of knowing that the client connection is gone.
To account for that, you should either:
implement a timeout in your application-layer data protocol. If you are expecting a client to send something to your server, and it does not do so for a certain amount of time, assume the client is gone and close the connection. During periods of idle activity, require clients to send a heartbeat command to your server at regular intervals to keep their connections alive. You can use the AContext.Connection.IOHandler.CheckForDataOnSource() method to wait for data to arrive, or you can use the AContext.Binding.SetSockOpt() method to specify an SO_RCVTIMEO timeout on blocking reads.
if you cannot change your data protocol, you can at least enable TCP-level keep-alives on the socket itself. In the server's OnConnect event, you can call the AContext.Binding.SetKeepAliveValues() method to enable keep-alives. The OS will then handle the keep-alives for you, and will invalidate the connection if the timeout elapses.
With that said, also make sure that your server event handlers are not swallowing Indy exceptions (derived from EIdException). That can also cause the server to not terminate threads correctly, if a connection is lost and Indy raises an exception about it but you are not allowing the server to process it. If you need to catch exceptions (for logging, etc), make sure to re-raise any EIdException-derived exception and let the server handle it.
I want to download a file from FTP. If the file is small (usually under 1000MB) it works. However, if the file is big I get an EIdReadTimeout. Why? Should I keep the connection alive? From what I know reading data has its own channel so I don't have to keep the connection alive.
What is odd is that the exception appears at the end of the Get (after Get successfully downloads the whole file): FTP.Get(Name, TempGzFile, TRUE, FALSE) !!!!
Documentation:
TIdFTP.ReadTimeout - Number of milliseconds to wait for an FTP protocol response.
TIdFTP.TransferTimeout - Timeout value for read operations on the data channel for the FTP
client.
By default ReadTimeout is set to 60sec and TransferTimeout to 10sec.
I a using Delphi XE7 (which I guess uses Indy 10). The Passive property for my IdFTP is set to false.
The FTP protocol uses multiple TCP/IP connections - one for the main command/response connection, and separate connections for data transfers. While a data transfer is in progress, the main command connection sits idle. Once the transfer is finished, the command connection receives a response.
If you are passing through a router/firewall that is not FTP-aware, the command connection is likely to get killed if it sits idle for too long during a large transfer. The connection is usually not killed "gracefully", so even the OS does not know the connection is gone. When TIdFTP then tries to read a transfer response that never arrives, it times out.
To account for that, use the TIdFTP.NATKeepAlive property to enable TCP/IP level keep-alives on the command connection during transfers. Set NATKeepAlive.UseKeepAlive to True, and set NATKeepAlive.IdleTimeMS (the idle timeout before keepalives start sending) and NATKeepAlive.IntervalMS (the interval between each keepalive) to suitable values.
Note, however, that IdleTimeMS and IntervalMS are only implemented for Windows 2000+, Linux, and BSD at this time. Other platforms use defaults provided by the OS (which tend to be very large). If you need to customize the values on those platforms, you can use the TIdFTP.OnDataChannelCreate and TIdFTP.OnDataChannelDestroy events to call TIdFTP.Socket.Binding.SetSocketOption() directly as needed.
I have a Datasnap application(Delphi 7) which uses TSocketConnectiom to connect to application server. If my application stays idle for a long time after opening a clientdataset, most of the times when i want to refresh the clientdataset the application freezes without raising any exceptions.It seems that the connection is dropped and the Socketconnection is not aware of that.I am experiencing this problem very often and I am not sure where can I find the solution. Could it be a bug in TSocketconnection?
Best Regards
Firewalls sometimes drop inactive TCP connections after some time to keep their cache usage low. In this case it helps to call some server method (maybe every five minutes).
If the "setup and teardown" code for the server side DataSnap session is not to resource-consuming, you can also disconnect and reconnect the DataSnap client between all actions. This will initiate a fresh TCP connection, execute, and close it.
I am using TClientSocket and TServerSocket to comunicate with a server the problem is that sometimes connection is lost either by the server issuing me the following exceptions : Error on WsaSend, acess violation etc or by the Client : Asychronious socket error.
Witch is the best method to recover from these errors and keep the connection open no mather what ?
There is no such thing as "keeping the connection open no matter what". What if the cable gets cut? The best you can do is to send a heartbeat on some interval to let intermediate routers know you are still interested in using that connection, and to carefully handle all errors, and, if necessary, re-establish the connection.
Great question... what you're receiving is WSAECONNABORTED (Asynchronous Socket Error 10053).
How did i prevent it from happening in MY code ? well, there's something called Keepalive, if you look carefully into the name, Keep-Alive, it meant to keep the connection alive, just send Null data to the connection (Can be One-way), that's all...
i made a Timer (named it TmrKeepAlive) and set its interval to 5000ms (5 seconds), More info on KeepAlive.
Edit: Also, if you don't want to write your own KeepAlive mechanism, check this out
When I call the function
IdFtp.List(myList, '', false);
afterwards I have logged in and changed the ftp directory, I get a socket-error #10054 exception ("Connection reset by peer.") occesionally.
When I call that function e.g. 20 times consecutively I get that exception 1 time.
That problem I have only encountered on Vista OS.
Does anybody know what the problem is or how I can avoid it?
Not much you can do about this, because the disconnection is done by the FTP server.
You have a few choices:
Increase (or disable) the timeout settings (every FTP server has a different name for it) on your FTP Server connection settings.
Tell server that you are alive by sending NOOP command periodically (switching to Passive mode can also help).
Catch that exception and reconnect silently (This is my preferred solution because we have many FTP servers and I don't trust the sys-admins to change the FTP server time-out settings).
Here is a screen-shot from FileZilla FTP server time-out settings:
Note that with the above settings, the FTP client will be disconnected after 2 min of non-activity.
setting that value to 0, will disable the time-out.
The FTP protocol uses multiple socket connections. Every time you call List(), a new socket connection is established to transfer the requested listing data. It sounds like the FTP server is not always closing the socket correctly at the end of a transfer.
In the component "IdFTP", change the following properties:
"Passive" = "False"
"TransferType" = "ftASCII"