![]() |
Closing a TCP/IP component connection the right way - Printable Version +- Atozed Forums (https://www.atozed.com/forums) +-- Forum: Indy (https://www.atozed.com/forums/forum-8.html) +--- Forum: Indy General Discussion (https://www.atozed.com/forums/forum-9.html) +--- Thread: Closing a TCP/IP component connection the right way (/thread-3940.html) |
Closing a TCP/IP component connection the right way - Ahmed Sayed - 03-12-2024 Hi, Let's say that, I have a TCP component with its connection opened with the server, whether it is TIdTCPClient, TIdHTTP, TIdFTP, etc. What is the correct way to close the connection without raising any exception especially if the server went down before doing so? I know that all of these classes inherit from TIdTCPClientCustom so there must be a common way to close them on that class level. The idea here is that I want to create something similar to std::unique_lock, std::unique_ptr, and std::lock_guard. Let's call it unique_connection<T> for instance. So, regardless of the template T which can be any class that inherits from TIdTCPClientCustom, whenever unique_connection goes out of scope it will close the connection without raising any exceptions whether the server is still running or not. I need this to make sure that there are no resources like sockets, or connections that are still open before the client gets destroyed. RE: Closing a TCP/IP component connection the right way - rlebeau - 03-12-2024 (03-12-2024, 04:08 PM)Ahmed Sayed Wrote: I know that all of these classes inherit from TIdTCPClientCustom so there must be a common way to close them on that class level. Simply call their Disconnect() method, which is inherited from TIdTCPConnection. It should not raise an exception, but if it does, just catch it. In the case of TIdFTP and various other higher-level protocol components, Disconnect() will send a goodbye message to the peer before shutting down the connection. If you don't want to send that message, Disconnect() has an optional ANotifyPeer parameter that you can set to false. (03-12-2024, 04:08 PM)Ahmed Sayed Wrote: I need this to make sure that there are no resources like sockets, or connections that are still open before the client gets destroyed. You don't need to worry about that. The client's destructor will shutdown the connection and close the socket if it is still active. RE: Closing a TCP/IP component connection the right way - Ahmed Sayed - 03-13-2024 (03-12-2024, 04:44 PM)rlebeau Wrote:(03-12-2024, 04:08 PM)Ahmed Sayed Wrote: I know that all of these classes inherit from TIdTCPClientCustom so there must be a common way to close them on that class level. The way I know it is that to close the connection from the client side, I have to do something similar to this: Code: IdHTTP->IOHandler->WriteBufferClear(); RE: Closing a TCP/IP component connection the right way - rlebeau - 03-14-2024 (03-13-2024, 10:28 PM)Ahmed Sayed Wrote: The way I know it is that to close the connection from the client side, I have to do something similar to this: Most of that stuff is unnecessary:
That being said, HTTP is not a stateful protocol, and TIdHTTP manages the socket connection internally for you, connecting and disconnecting it as needed. You should never have to disconnect TIdHTTP manually. RE: Closing a TCP/IP component connection the right way - Justin Case - 07-09-2024 Can I chime in here and also ask... What happens if one side of the connection doesn't send a quit type of message but just disconnects? - or the connection is lost (eg isp failure, ethernet cable gets yanked out the wall etc) ? Does OnDisconnect() still get triggered? RE: Closing a TCP/IP component connection the right way - rlebeau - 07-09-2024 (07-09-2024, 07:04 PM)Justin Case Wrote: What happens if one side of the connection doesn't send a quit type of message but just disconnects? Are you asking about the client side or the server side? On the server side, you will still get an OnDisconnect event triggered. That is not dependent on any bye/quit message. On the client side, nothing will happen unless you try to read/write data after the disconnect occurred, in which case you will then get an exception, such as EIdConnClosedGracefully (if the disconnect is graceful and intentional) or EIdSocketError or similar otherwise. (07-09-2024, 07:04 PM)Justin Case Wrote: or the connection is lost (eg isp failure, ethernet cable gets yanked out the wall etc) ? Nothing will happen until the OS deems the connection is actually lost and starts reporting errors on it, which can take time. Until then, the connection is just sitting idle. Remember, TCP is designed to survive outages and recover from them when possible. So, if you try to read data on a connection that is in this state, it will simply drain the InputBuffer as normal until it can't satisfy further reads, and then it will wait on the socket until new data arrives or an error occurs. And, if you try to write data, it will continue to be buffered inside the socket as normal until the buffer is full, at which time the socket will block further writes until the OS flushes the buffer or an error occurs. (07-09-2024, 07:04 PM)Justin Case Wrote: Does OnDisconnect() still get triggered? On the server side, yes (eventually - consider using read timeouts or TCP keep-alives to lower the time needed to detect lost connections). On the client side, the OnDisconnect event is not asynchronous. It is simply triggered when the app explicitly Disconnect's the client while it is still in an open state. RE: Closing a TCP/IP component connection the right way - Ahmed Sayed - 07-10-2024 Hi again, I am working on a Push notification service that uses a mix of indy HTTP and TCP components. So, I use HTTP to pull any pending large number of messages to the user and TCP on both sides to push and receive anything written to the socket. Let's say that the connection dropped for any reason. Now, on the client side, I have a timer or a worker thread looping to read anything that gets sent to the client but I am always checking if the connection is on via the "Connected" method. My question is, is that enough to know that the connection has been lost, or do I need to read from the socket to raise the proper errors accordingly? Knowing that the client app should not raise exceptions in the user's face everything should be handled internally. RE: Closing a TCP/IP component connection the right way - rlebeau - 07-10-2024 (07-10-2024, 12:09 AM)Ahmed Sayed Wrote: I am always checking if the connection is on via the "Connected" method. You should not be doing that. Just have your timer/thread read normally and let Indy raise an exception if the connection is closed. (07-10-2024, 12:09 AM)Ahmed Sayed Wrote: My question is, is that enough to know that the connection has been lost, or do I need to read from the socket to raise the proper errors accordingly? Since Indy uses blocking sockets, a socket read is necessary. But Indy will read from the socket for you when its InputBuffer doesn't have enough bytes to satisfy a read operation. You don't need to read from the socket yourself, such as with the Connected() method (which does a socket read internally). (07-10-2024, 12:09 AM)Ahmed Sayed Wrote: Knowing that the client app should not raise exceptions in the user's face everything should be handled internally. Simply wrap any read/write operation you perform in a try..except (Pascal) or try..catch (C++) block. Indy uses exceptions for all of its error reporting. |