Board index » delphi » Indy 9.0 - interrupt blocking operation?

Indy 9.0 - interrupt blocking operation?

Hello newsgroup

I've got a problem with an FTP program I'm creating (the .zip file
containing source that I'm using is labelled 'IndyWin32_9_00_11_Src.zip',
for reference).
I've set a timeout on my TIdFTP component (90 seconds), but occassionally
(not often, but frequently enough to be a problem), when I've set some
action in motion (ChangeDir, say), it won't timeout where's there's been no
response from the server (most often observerved when my modem connection is
a bit flaky, with a number of packets being dropped).
Instead it'll just sit, waiting indefinately with no way to cancel the
operation other than to 'Reset' via the IDE. Can someone tell me whether
there's a more elegant way to force-interrupt the blocking socket?

Many thanks in advance

 

Re:Indy 9.0 - interrupt blocking operation?


Quote
James Porter <na@not_an_address.com> wrote in message

news:3e3ff7ec@newsgroups.borland.com...
Quote
> Hello newsgroup

> I've got a problem with an FTP program I'm creating (the .zip file
> containing source that I'm using is labelled

'IndyWin32_9_00_11_Src.zip',

Quote
> for reference).
> I've set a timeout on my TIdFTP component (90 seconds), but
occassionally
> (not often, but frequently enough to be a problem), when I've set
some
> action in motion (ChangeDir, say), it won't timeout where's there's
been no
> response from the server (most often observerved when my modem
connection is
> a bit flaky, with a number of packets being dropped).
> Instead it'll just sit, waiting indefinately with no way to cancel
the
> operation other than to 'Reset' via the IDE. Can someone tell me
whether
> there's a more elegant way to force-interrupt the blocking socket?

Well, there is an abort method.  You should try calling this from the
main thread.  If you are not running the FTP in a seperate thread,
then run the FTP in a seperate thread :)

Rgds,
Martin

Re:Indy 9.0 - interrupt blocking operation?


Quote

> Well, there is an abort method.  You should try calling this from
the
> main thread.  If you are not running the FTP in a seperate thread,
> then run the FTP in a seperate thread :)

I tried this 'cos of another post.  It seems to work OK.  The abort
method causes an immediate exception of various types, (presumably
depending on what exactly the TidFTP was doing when the abort got
called), but I always do get an exception, allowing the thread to
clean up & exit.

Rgds,
Martin

Re:Indy 9.0 - interrupt blocking operation?


Hi Martin, thanks very much for responding.

To be perfectly honest, I don't have any experience with multi-threaded
program writing, and I was hoping to get away with just 'main program thread
+ AntiFreeze'.
I appreciate your suggestion, but you'll have to excuse my ignorance - in
broad terms, could someone explain how giving a separate thread
responsibility for conducting FTP operations is different from just carrying
out the same operations from the main program thread?
I'll try to make my question clearer... hmm, how is a separate thread any
better placed to 'break out' of a blocking socket procedure (like ChangeDir
etc.) when no timeout occurs, then the the main program thread?

How *would* that thread:

- cut in on the blocking operation
- know at what point to interrupt it

...and why couldn't the same thing just be carried out from the main thread?

Apologies, I suspect my particular perspective on things might be preventing
me from understanding these issues, but if anyone could clarify I'd be very
grateful!

Quote
> Well, there is an abort method.  You should try calling this from the
> main thread.  If you are not running the FTP in a seperate thread,
> then run the FTP in a seperate thread :)

> Rgds,
> Martin

Re:Indy 9.0 - interrupt blocking operation?


Quote
James Porter <nowh...@noplace.com> wrote in message

news:3e403edf@newsgroups.borland.com...

Quote
> Hi Martin, thanks very much for responding.

> To be perfectly honest, I don't have any experience with
multi-threaded
> program writing, and I was hoping to get away with just 'main
program thread
> + AntiFreeze'.
> I appreciate your suggestion, but you'll have to excuse my
ignorance - in
> broad terms, could someone explain how giving a separate thread
> responsibility for conducting FTP operations is different from just
carrying
> out the same operations from the main program thread?

It leaves the main thread unblocked at all times.  This means that
timer, button-click etc. events are still fired no matter whether the
FTP thread is connecting, listing getting, putting, whatever.  This
means that you can call TidFTP.abort even if an FTP operation is
currently blocking it's own thread.

Quote
> I'll try to make my question clearer... hmm, how is a separate
thread any
> better placed to 'break out' of a blocking socket procedure (like
ChangeDir
> etc.) when no timeout occurs, then the the main program thread?

> How *would* that thread:

> - cut in on the blocking operation

It wouldn't - it would be blocked.  The main thread would call
TidFTP.abort, (diect via the thread reference, or by adding an
'abort' method to the thread class).  This call will be executed in
the context of the main thread & just return.  This causes an
exception in the FTP thread, 'interrupting' any blocking operation.

Quote
> - know at what point to interrupt it

You could use a main-thread timer, set to the maximum time you are
willing to wait for an operation to complete.   If the FTP operation
in the thread completes or excepts, post a message to the main thread
that, as well as indicating successor otherwise to the user, diables
the timer.   If the timer fires, you can call abort & indicate the
timeout to the user, log it, whatever.

Quote
> ...and why couldn't the same thing just be carried out from the

main thread?

Because if the main thread is blocked, timer messages, (all messages,
in fact), will not be handled.

If you want to stick with one thread, the TidAntiFreeze should
work-ish during puts & gets, AFAIK.  I don't think it helps during
connects.  Not sure about lists.  Indy in the main thread just does
not work very well & leads to poor quality apps. with unfriendly
'hourglass-like' pauses, like OE.

Rgds,
Martin

P.S. IMHO, if you want to work with the main thread only, you should
look at ICS.

Re:Indy 9.0 - interrupt blocking operation?


Well, to stop a blocking call from a different thread, you don't have
many choices: you must for the thing it's waiting on either to return
or to disapear. The simplest way to do that is to force it into an
error condition and handle that error afterward. With a blocking socket
call, you can, for exemple, close the socket it's waiting on (reading
from). This will trigger an exception in the target thread that you'll
have to catch. If you also took care of setting an "interrupted" flag,
you can simply discard the exception...

Good luck,
Stephane

Quote
James Porter wrote:
> Hello newsgroup

> I've got a problem with an FTP program I'm creating (the .zip file
> containing source that I'm using is labelled 'IndyWin32_9_00_11_Src.
> zip', for reference).
> I've set a timeout on my TIdFTP component (90 seconds), but
> occassionally (not often, but frequently enough to be a problem),
> when I've set some action in motion (ChangeDir, say), it won't
> timeout where's there's been no response from the server (most often
> observerved when my modem connection is a bit flaky, with a number of
> packets being dropped).  Instead it'll just sit, waiting indefinately
> with no way to cancel the operation other than to 'Reset' via the IDE.
> Can someone tell me whether there's a more elegant way to
> force-interrupt the blocking socket?

> Many thanks in advance

Re:Indy 9.0 - interrupt blocking operation?


James, Martin - thank you both very much, that clears a lot up. Looks like
I'll have some redesigning to do, but it sounds as though the separate
thread route is really the way to go.

Appreciate your time - best regards

Re:Indy 9.0 - interrupt blocking operation?


In article <3e411...@newsgroups.borland.com>, na@not_an_address.com
says...

Quote
> James, Martin - thank you both very much, that clears a lot up. Looks like
> I'll have some redesigning to do, but it sounds as though the separate
> thread route is really the way to go.

> Appreciate your time - best regards

Hi, James. Seems that I am having the same problem as you. I have a FTP
Client APP built with Indy in Delphi 5 which occasionally hangs with no
exception, blocking the main thread appearently doing nothing.

By now I have abandoned the attempt to solve the problem, as I haven't
catched the cause yet :-( so I am trying to work aroudnd it, basically
to disconnect and reconnect in case of a hang.

I hope you'll be patient enough to read this (I hope in anyone else too!
:-] )

I tried to use IdAntiFreeze and a TTimer to catch the error forcing an
exception by ABORting. This is a snippet:

-----------------------------------------------------------------------
1. A smart routine that gets a file
-----------------------------------------------------------------------
function TMainFrm.SafeGet (asRemSrc, asLocDst : string) : boolean;
var
    lbDone, lbGood : boolean;
    liTries : integer;
begin
    lbDone := false;     lbGood := false;     liTries := 0;
    FailTimer.Enabled := true;
    while (not lbDone) do begin
        try
            MyFTP.Get(asRemSrc,asLocDst,true,false);
            lbDone := true; lbGood := true;
        except
            on E:Exception do begin
                Inc(liTries);
                if (liTries>=5) then begin
                    lbDone := true;
                    lbGood := false;
                end;
            end;
        end;
    end;
    FailTimer.Enabled := false;
    Result := lbGood;
end;
-----------------------------------------------------------------------

Before a loop I enable a timer to catch a timeout. the presence of a
TIdAntiFreeze component seems to allow the Timer to run.
I simpilfied the operation, as the exception could be triggered other
than my Abort method, anyway we can suppose by now that the Abort method
is the only reason for the exception to fire at this moment.

Now let's examine the FailTimer event, which is triggered any second
(the Timer has an interval of 1000):
-----------------------------------------------------------------------
2. FailTimer event
-----------------------------------------------------------------------
procedure TMainFrm.FailTimerTimer(Sender: TObject);
begin
    // first of all avoid loops
    FailTimer.Enabled := false;
    Inc(iiIdleTime);
    // more than 20 seconds of inactivity...
    if (iiIdleTime>=20) and (MyFTP.Connected) then begin
        Inc(iiTotalFail);
        if (iiTotalFail>10) then begin
            ibStopped := true;
        end
        else begin
            MyFTP.Abort;
            MyFTP.Quit;
            MyFTP.Connect;
            if (isCurDir<>'') then MyFTP.ChangeDir(isCurDir);
        end;
    end;
    FailTimer.Enabled := true;
end;

-----------------------------------------------------------------------
When 20 seconds pass without ANY FTP action, I assume there is a{*word*154}
command. I set the buffer sizes to 256 bytes, and on any activity I
reset the iiIdleTime to zero, it means on OnStatus, OnWork, OnWorkBegin,
OnWorkEnd events.

This seems not to work, as it seems that not in all the cases the Abort
method raises an exception.

A) Could this be related to the fact that I do not wait any time between
the MyFTP.Abort and the MyFTP.Connect?

B) Have you then solved this using threads? If so, please, can you give
me a hint on the implementation? I am not very fond on threads dealing
with FTP.

I appreciate your time too, believe me!
Best regards

----------------------------------------
Ing. Piero Salandin
piero.salan...@eriador.it
icq#139345810
----------------------------------------

Other Threads