im using indy10 for my communications, and sometimes when a client disconnects it raises an exception, i was wondering whats the safest way to disconnect a connection (TIdContext) ?
and what should i do on the OnDisconnect even and similar?
thanks.
Raising an exception is normal behavior. Indy is designed to make heavy use of exceptions, not only for error handling but also for internal notifications and such. OnDisconnect is fired when TIdTCPServer detects that the connection is finished, either because the client disconnected (and TIdTCPServer handled the exception for you) or because an uncaught exception occured in your OnExecute handler code. Either way, use OnDisconnect to perform any cleanup you need. TIdTCPServer will close the socket for you after the OnDisconnect event handler exits.
I just want to add something about sockets internal work (TCP) that I know:
All that server and client does, they sends pieces of data to each other. Server differs from the client only so that he is passive until any client don't send a connection request first. But if client want or forced to break the connection, all is need to do is stop send data to server. To gracefully close a connection client may send special data about this event, like saying "goodbay" by phone, but this is not absolutely required. Simply imagine phone call from you (client) to any service (server). You start conversation with "hello" and service worker responds. If you accidently press reset on your phone, call will lost. But service still continue his work. And you may make call it again. Nothing bad happens from that.
All what you need to care about is stable and correct client and server work by itself. Check incorrect sending and receiving data. Try to reconnect when it needed from client. If some exception throws inside client it must be processed as needed and its normal situation when current connection was lost by such forced events.
Everything else has already answered by Remy Lebeau.
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 have a server application which runs on a Linux machine. I can connect this application from Windows/Linux machines and can send/recieve data. After a few hours, something occurs and I get following error on the client side.
On Windows: An existing connection was forcibly closed by the remote host
On Linux: Connection timed out
I have made a search on the web and found some posts which suggest to increase/decrease OS's keep alive time. However, it didin't work for me.
Can I found a soultion to this problem or should I simply try to reconnect to the server when the connection is forcibly closed?
EDIT: I have tracked the situation. I sent a data to the remote node and sent another data after waiting 5 hours. Sending side sent the first data, but whet the sender sent the second data it didn't response. TCP/IP stack of the sender repeated this 5 times by incrementing the times between retries. Finally, sender reset the connection. I can't be sure why this is happening (Maybe because of a firewall or NAT - see Section 2.4) but I applied two different approach to solve this problem:
Use TCP/IP keep alive using setsockopt (Section 4.2)
Make an application level keep alive. This is more reliable since the first approach is OS related.
It depends on what your application is supposed to do. A little more information and perhaps the code you use for listening and handling connections could be of help.
Regardless, technically a longer keep alive time, should prevent the OS from cutting you off. So perhaps it is something else causing the trouble.
Such a thing could be router malfunction or traffic causing your keep-alive packet to get lost.
If you aren't already testing it on a LAN (without heavy trafic) I suggest doing so.
It might also be due to how your socket is handled (which I can't determine from your question)
This article might help.
Non blocking socket with timeout
I'm not used to how connections are handled on Linux, but I expect the OS won't cut off a connection unnecessary.
You can re-establish connection as a recovery, but you need to take into account that not all disconnects are gentle, and therefore you could end up making recovery on a connection you actually wish to be closed.
Since it is TCP, it will do its best to make a gentle disconnect, but you can send a custom message telling the server or client not to re-establish the connection right before disconnecting. That way you be absolutely sure, despite that it should be unnecessary to do so.
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
If a client connects to a server over a normal tcp connection, and then later on the client's connection cuts out, the server will get (assuming active mode) {tcp_closed,Socket}. But there are cases where the server won't know that the client has disconnected, such as power failure or crashing and such (I believe, I could be wrong). In these cases, the client is gone but the server still believes it's connected. If the server attempts to send the client a message in these cases, will it assume that the client gets the message or will the tcp stack sort that out on the low level and the server gets back some kind of error?
I know this is a simplistic question, but I've been having trouble testing it myself, as I can't get a client to catastrophically fail like I need it to (even kill -9 isn't doing it). Does anyone have any experience with this?
The answer depends. When you try to send out data, the kernels TCP window will slowly fill until it can't take any more data. Then your send will block because the internal kernel buffer is full. TCP has some timers which will trigger after some time. When that happens, the kernel will error the send request, Erlangs VM runtime will transform it into {error, Reason}, where Reason is the posix() error message from the underlying system.
If you want to be sure the data got through, you have to acknowledge it on the stream the other way. Or you can make the data idempotent so you can resend it without trouble. It is especially important if the other endpoint, the client, is a device like a mobile phone where disconnects will happen all the time.
To test it, you can block the communication with a firewall rule on lo.
I'm looking to detect local connection loss. Is there a mean to do that, as with the events on the Corelabs components ?
Thanks
EDIT:
Sorry, I'm going to try to be more specific:
I'm currently designing a prototype using datasnap 2009. So I've got a thin client, a stateless server app and a database server.
What I would be able to do is to detect and handle connection loss (internet connectivity) between the client and the server app to handle it appropriately, ie: Display an informative error message to the user or to detect a server shutdown to silently redirect on another app server.
In 2-tier I used to manage that with ODAC components, the TOraSession have some events to handle this issues.
Normally there is no event fired when a connection is broken, unless a statement is fired against the database. This is because there is no way of knowing a connection loss unless there is some sort of is-alive pinging going on.
Many frameworks check if a connection is still valid by doing a very small query against the server. Could be getting the time from a server. Especially in a connection pooling environment.
You can implement a connection checking function in your application in some of the database events (beforeexecute?). Or make a timer that checks every 10 seconds.
Spawn a thread on the client which periodically sends some RPC 'Ping' or 'Heartbeat' commands to the server.
if this fails, the client knows that something happened to the connection
if the server does not hear the client anymore for some time period (for example, two times the heartbeat interval), he can conclude that the client disconnected, however this requires a stateful server (and your design is stateless so it would require event processing in a secondary system, which could be fed through a message queue)