How to handle Connection Reset By Peer exception of TIdHTTP.Get request? - delphi

In my VCL application, I use TIdHTTP.Get() to retrieve data from a RESTful web service. In my application, I use the following code:
var
HTTP: TIdHTTP;
ws: WideString;
begin
ws := HTTP.Get('http://www.restfulwebservice.com/' + ObjectId);
end;
My application always runs on a Windows workstation, and I never want to close it. However, from time to time, it reports a nasty exception Connection Reset By Peer. This usually happens after some inactivity.
In such cases, I must close the application and re-open it again, because I have no idea how to handle this exception. I want to properly handle it (within a try..except block?) to re-open the connection, so there is no need to close and re-run my app.
Are there any practices on how to catch and handle the above mentioned exception? My research showed me some examples of TIdTCPServer, but not TIdHTTP.
Im using Delphi Berlin 10.1 Subscription Update 2 on Windows 7 x64.

Related

TidCustomTCPServer.Active := False, never returns

I downloaded some interesting code from Indy 10 TIdTCPServer and compiled and ran it. It's a bit messy and it probably needs work but it's a good foundation for something interesting. At least I don't have to post all the code here. Anyway, I decided that the ExampleServer needs to be de-activated first, not just freed in OnDestroy. So I added:
procedure TServerPushExampleForm.FormClose(Sender: TObject);
begin
ExampleServer.Active := False; // bug here - never returns
end;
To try to debug this, I added IdCustomTCPServer.pas to the project and stepped into it.
An exception is raised in TIdCustomTCPServer.StopListening; at the line LListener.WaitFor; This exception is trapped in the exception handler in TIdListenerThread.Run; but the E.message isn't retrieved there, so I had to modify the code there to get the message:
"Operation Aborted"
I traced it further after that, but the code execution eventually comes back to the same exception handler.
Is this a bug or is it just better to never set the Active property to False? In my tests, if I close the app and let the RTL manage all the free'ing. The infinite loop doesn't occur (the app does actually close)
The exception is normal behavior.
Indy uses blocking sockets.
TIdListenerThread runs a loop waiting for clients to connect. Each wait is a blocking operation.
When the server is being deactivated, it closes its listening socket(s), causing pending socket operations to abort, and then the listening thread(s) are terminated. The abort exception is handled internally.
The server's destructor also sets Active=False, so whether you deactivate explicitly or not, the server will be deactivated.
This, in if itself, is not causing your hang. Typically, the only way setting Active=False can ever hang is if a server event handler tries to sync with the main UI thread synchronously while the main thread is blocked waiting for the server to deactivate. Classic deadlock scenario.
That does not appear to be the case in the demo you linked to, though (the only sync being used is asynchronous instead). So, something else is likely going on that your debugging hasn't reveiled yet. There should be no hang.

Delphi FTP timeout exception

I'm using Indy's FTP.
It works perfectly with what I want, my only issue is that if the system isn't connected to the Internet or the server is down then it displays a TimeOut exception on screen.
I can't seem to be able to find out how to catch the exception.
I just want it to, instead of show an error, be able to show my own message to reassure the user that there is no issue. If that made sense.
I've used try excepts before and they work just not here it seems.
Could someone give me an idea or some example code of where and how to write the exception catcher here?
Thanks
EDIT:
Sorry, I was away from my normal PC so couldn't post code.
Actually I just retried and it did catch it, thanks for the note about the debugger always showing the exception.
However, after my custom message I also get a 'Connection Closed Gracefully' message. (I ran it outside of debugger)
How/Where can I catch/stop that one?
Also, it sometimes returns a message from my server, such as 'Cant connect more than 3 times on same account' or whatever. Can I stop/catch that aswell?
Thanks
Here:
Form1.ftp.Host := 'HOSTNAME';
Form1.ftp.User := 'USERNAME';
Form1.ftp.password := 'PASSWORD';
Try
Form1.ftp.Connect;
Except on E : Exception do
begin
ShowMessage('Timeout Error, dont worry');
end;
end;
Like most components in Indy, TIdFTP does everything synchronously, and errors are reported as exceptions. Standard try/except blocks work just fine. Indy is designed for that.
If you are seeing a Connection Closed Gracefully message appear when running your app outside of the debugger, it means you tried to perform a socket operation after the socket was already disconnected, and you did not catch the EIdConnClosedGracefully exception that was raised into your code. For instance, if Connect() fails, it calls Disconnect() internally before raising an exception to you. Don't call any other TIdFTP methods in that situation, other than Connect() again if needed.
As for error messages sent by the FTP server, they are usually reported by raising EIdReplyRFCError (or derived) exceptions, which you can catch in your code.

Too many connections when developing

I'm trying (with a lot of help from this community) to put together my first client/server app.
I am using Indy 10 and Delphi Xe2, but suspect my problem does not lie with those, but rather with how soockets work (wizardy and black arts, if you ask me).
Because I often hit breakpoints of exceptions and step through my code before pressing Alt+F2 to halt, my next runs often hit exception "already connected" and eventually I get "too many connections".
How can I tidy this up?
(also, does anyone have a demo which uses try ... except, ratehr than try ... finally as in the Indy demos?)
"already connected" occurs on the client side when you call Connect() while Connected() still returns true. That usually occurs if you disconnect and leave unread data in the IOHandler.InputBuffer. Try clearing the InputBuffer before reconnecting. This is commonly encountered, so a near-future update to Indy may address that issue.
"too many connections" means that you set the server's MaxConnections property to a positive non-zero value and that many simultaneous clients are already connected to the server when a new client tries to connect. If you do not think that you are making that many simultaneous connections, then it usually means that you are not managing the connections correctly in your server code so disconnected clients get cleaned up correctly. The most common cause of that is putting exception handlers in your code that catch and swallow Indy's internal exceptions to itself. If you do catch exceptions, be sure to re-raise any that derive from EIdException and let the server handle them internally.

Is it possible to terminate a TCPClient immediately?

My app sends data to a Server using a TidTCPClient. The Server uses a TidTCPServer. All works fine and I am now trying to handle unexpected situations.
When I disconnect the network cable between server and client, and then try to close the client, it waits for a long time, until it finally closes:
TCPClient.IOHandler.InputBuffer.Clear;
TCPClient.Disconnect;
TCPClient.Free;
TCPClient.Free is the place where it waits. This is sometimes 30 seconds, sometimes even longer.
Is there a way to terminate a TCPClient immediately, no matter what it is doing at that moment?
You should be clearing the InputBuffer after calling Disconnect(), not before.
In any case, there is no reason for a socket to cause such a hang when disconnecting/freeing the TIdTCPClient, unless you have messed around with the socket's LINGER options. So I have to suspect your own code is at fault first. Which version of Indy are you using? Do you have any event handlers assigned to the TIdTCPClient? Have you tried stepping through TIdTCPClient's destructor in the debugger to see what is really happening?
It probably waits for a timeout. Look at the properties of the component to lower the timeout value

The connection does not timeout while using Indy

I want to download a file from internet and I imagine this should be a simple task. Trying several different approaches I have found that each one has its own drawback.
The main issues are:
Application freezes until it downloads the file
Application freezes forever if the Internet connection is lost/server does not respond.
(details:
How to retrieve a file from Internet via HTTP?
The connection does not timeout while downloading file from internet )
So, finally I used the suggestions I got from several people to use "pro" libraries such as Indy. However, Indy is not much better than the pieces of code I have tried (but it is way much larger and difficult to maintain). While using Indy the application does not freezes only for short periods so it is still (somehow) usable. However, the application cannot be shut down until the download finishes (never if the Internet connections gets broken).
Other people reported the same problem: http://borland.newsgroups.archived.at/public.delphi.internet.winsock/200609/0609079112.html
https://forums.embarcadero.com/thread.jspa?threadID=25199&tstart=90
So, there is some hacking I had to do to TIDAntiFreeze in order to make it work?
Also, the ConnectTimeout property is not recognized.
fIDHTTP := TIDHTTP.Create(NIL);
fIDHTTP.ConnectTimeout:=5000;
Should I drop Indy and return to original idea of downloading the file in a separate thread and end the thread when it does not respond (at least this way I get rid of 3rd party libraries)? There will be unforeseen side effects if I do this?
Using: Delphi 7, Indy 10.1.5 10.5 (probably).
Thanks
You probably need to use Indy the Indy way: using threads. Indy was specifically designed to work in blocking mode, because that's how most internet protocols work (example: with HTTP, at protocol level, you send a request, then you read the response. You don't send and receive at the same time). TIdAntiFreeze is supposed to help you use some Indy functionality without dealing with threads; I never used that because, at least conceptually, it's an ugly hack.
If you don't want to deal with threads then you should take a look at ICS - it was designed to be used in async mode, without threading. It doesn't need the equivalent of TIdAntiFreeze because it's not blocking. You start a download and you handle some events to get progress and completion notifications. ICS is just as well-known, professional and wildly used as Indy.
It's not too difficult to solve these sorts of problems. The first thing you have to do is make sure that you have properly handled error handling. If something fails then make sure everything cleans up properly. Beyond that make sure the downloading code is part of a separate thread. If there is any problem you can always terminate the thread from your main program. Here's the code (for downloading only, not the threading) which is working fine for me.
with TDownloadURL.Create(nil) do
try
URL := 'myurltodownload.com';
filename := 'locationtosaveto';
try
ExecuteTarget(nil);
except
result := false;
end;
if not FileExists(filename) then
result := false;
finally
clear;
free;
end;

Resources