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.
Related
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.
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.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
All Indy SMTP examples I have seen show TIdSMTP being instantiated at the start of the email send routine and freed at the end.
I have written an SMTP email sender prototype application, based upon Indy 10 components, that normally works with no issues. (It can send in the clear or via explicit or implicit TLS.) It instantiates TIdSMTP on startup and frees it on closing.
I have just had a situation where IdSMTP.Send threw an exception saying that SMTP was not connected. This would be unremarkable except for the fact that I have a test for IdSMTP.Connected, immediately prior to my IdSMTP.Send, that reported that SMTP was connected. My program could no longer be made to send emails because it thought it was connected but in reality it wasn't. The only solution was to restart the program. When testing of this prototype application is completed the code will be incorporated into a server service that cannot just be restarted to fix this sort of problem.
The problem could have been avoided or, at least, worked around if I had instantiated my TIdSMTP class within my email send procedure; in the unlikely event of this re-occurring the IdSMTP object would be freed at the end of the procedure and re-instantiated the next time it gets called.
The reason I didn't architect my solution as in the examples was that re-instantiation of TIdSMTP for each email send also requires that the IdSMTP object reconnect to the email server for each send. This can be a very slow process - of the order of 5 to 10 seconds for external email servers - and this overhead can be avoided by not re-instantiating TIdSMTP each time.
So my question is: is this (or similar issues) the reason why all examples show re-instantiation each time? Or, is it simply to show a complete, contained example? The latter was how I interpreted it.
If you have experience with the pros and cons of this issue, please provide your opinions, and thoughts.
If there exists a definitive best practice, that would useful to hear about too.
All Indy SMTP examples I have seen show TIdSMTP being instantiated at the start of the email send routine and freed at the end.
They are just examples. Obviously production code can be more complex. You can reuse a single TIdSMTP object multiple times.
I have a test for IdSMTP.Connected, immediately prior to my IdSMTP.Send, that reported that SMTP was connected.
Let Send() fail and raise an exception if the connection is not available. Indy uses exceptions for error reporting, so make use of them, don't avoid them. Connected() can report a false positive. If the IOHandler.InputBuffer has unread data in it, Connected() will return true, even if the underlying socket is closed. This is by design. Don't rely on Connected() to drive your logic.
My program could no longer be made to send emails because it thought it was connected but in reality it wasn't.
After Connect() succeeds, if you get any exception that is not derived from EIdRFCReply, you should Disconnect() the connection and Clear() the InputBuffer (if there is still an IOHandler assigned - Disconnect() will free it if it was created internally by Connect()) before calling Connect() again. Connect() raises an exception if Connected() returns true, so you have to manually clear the condition that causes that (unread data) if an unexpected error occurs.
Try
If not SMTP.Connected then SMTP.Connect;
...
Except
On E: EIdRFCReply do
Begin
// an SMTP command failed, but the connection is still stable
...
End;
On E: Exception do
Begin
SMTP.Disconnect(False);
If SMTP.IOHandler <> nil then SMTP.IOHandler.InputBuffer.Clear;
...
End;
End;
In general, you should keep connections to the outside for as short a time as possible. I assume that this program/service doesn't send emails 24h/7d continously, but in response to some external event (a timer or other event that triggers "now it is time to send"), and then it sends one (or more) emails at that point.
The way I would code this is to instantiate the TIdSmtp at the start of this event and then free it at the end. This way, you would have a freshly instantiated connection to the outside every time.
If your program only sends a single email on every event, then you could perhaps code it such that if the sending fails, then signal that on the next event, you should re-instantiate the TIdSmtp variable, something along these lines:
PROCEDURE SendMsg(...)
BEGIN
IF NOT Assigned(SMTP) THEN SMTP:=TIdSmtp.Create(NIL);
TRY
... Your code to send one or more emails ...
EXCEPT
FreeAndNIL(SMTP);
... Perhaps Re-Raise exception, if outer layer needs to know ...
END
END;
This way, the SendMsg routine is self-restarting in case of error. Of course, some more error checking (what kind of exception was caught) would be advisable, but I expect you get the general idea...
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.
I have a service written in Delphi 2007 in which I'm trying capture any unknown exceptions. Assigning a method to the on exception doesn't seem to work ('Forms.Application.OnException:=UnknownApplicationException'). The 'UnknownApplicationException' doesn't appear to get called - I attribute this to the fact that there is no form in the application so the method never actually gets assigned. Aside from this, I've also tried creating an exception on a timer (after commenting out 'Forms.Application.OnException:=UnknownApplicationException' so that it does not interfere). The timer triggers 60 seconds after the service has started up:
procedure TProcessScheduler.Timer1Timer(Sender: TObject);
begin
try
Raise Exception.Create('THIS GIG SUCKS');
except
LogEvent(Name,rsUNKNOWN_EXCEPTION,EVENTLOG_AUDIT_FAILURE,0);
ExitCode:=-1;
Halt;
end;
end;
The exception never seems to get captured - the service starts up and after 60 seconds when this timer triggers, I hear a windows error sound but don't see any error dialog - perhaps this could be due to the fact that the application is a service? The 'Halt' never gets called and the application keeps running (i assume its waiting for someone to click ok on the invisible error dialog that it created). Any ideas why the code under the 'except' doesn't get called? Thanks in advance! KP
Reassigning Forms.Application.OnException is a bad idea, as TServiceApplication.Run() does this itself. You either do it before, then your assignment won't have an effect, or you do it afterwards, in which case you remove the exception handling mechanism that has been put into place.
If you leave the handling in place, then all exceptions will be logged to the Windows Event Logger, which seems a reasonable thing to do from a service.
A couple of notes:
As you are raising an exception within a try-except block, it should not trigger any Application.OnException handler, simply because the exception isn't unhandled.
How have you determined that the Halt doesn't get called? Does the exception get logged through your LogEvent?
In a Service application ExitCode and Halt don't function the way you would expect them to in a normal windows application. A service isn't stopped by calling halt, it should be stopped by going through the Windows' Service Control Manager.
If the except part of your try-except block is indeed not reached, it means that Windows has cut in because something has happened that it isn't happy with. That could be something in the LogEvent method you are calling. If that shows a dialog or if that raises an exception as well, the ExitCode and Halt won't be reached.
A service doesn't normally have a desktop associated with it, so showing dialogs isn't going to work.
If you need the service to show dialogs (bad idea by the way, services are intended to run without user interaction), you need to make it interactive and have it run under another user account than the normal "system" account that services run under. You do this through the services manager.
Why are you setting Forms.Application? AFAIK a service uses the Application variable declared in SvcMgr, which is declared as:
var
Application: TServiceApplication = nil;
Moreover a service should not display any dialog, it may not have access to the user desktop, and your dialog will hang the service. There are ways to display a dialog anyway, but services could also run when no human user is watching the screen.
Log events to the event log (or if you don't like it to a file, but the event log has several useful features, including remote access).
I create my own version of the SvcMgr.pas file to eliminate the in-place hook to the Application global exception handler so that I can instantiate my own. I do this because 1) I could find no other simple way of doing this, and 2) since this unit is a stand-alone unit that is only included with Windows Services then the effect on other units is minimal. You can download the code from my web-site to see how this works.