BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

EIdClosedSocket and TidcmdTCPServer and Freeze on close

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Internet Winsock
View previous topic :: View next topic  
Author Message
Clive Walden
Guest





PostPosted: Fri Sep 22, 2006 11:46 pm    Post subject: EIdClosedSocket and TidcmdTCPServer and Freeze on close Reply with quote



I have a problem that my server freezes when I try and set cmdTCPServer.Active to false when I have
clients connected.

However, it only freezes when I try to add a message to a memo on the main form in the onDisconnect
event.

There is no problem when the onDisconnect event is called in the normal course of events (i.e. a
client disconnects), only when I try to set Active to false.

Here is the relevant code:
(FAdminFrm is the main form.)

==============procedure TdmTCPServer.tcpServerDisconnect(AContext: TIdContext);
var
Client : TMyClient;
begin
{ Retrieve Client Record from Data pointer }
Client := Pointer(AContext.Data);
FAdminFrm.AddToLog('Disconnecting: '+Client.Name +
' : '+TimeTostr(Now) +
' Addr: '+Client.IPAddress);
{ Remove Client from the Clients TList }
FClients.Delete(Client.ListLink);
{ Free the Client object }
Client.Free;
AContext.Data := nil;
CoUnInitialize;
end;

procedure TfrmTCPServerAdmin.AddToLog(const msg: string);
begin
memLog.Lines.Add(msg); // Application hangs here!!!
end;


=================
When tracing into AddToLog msg does indeed contain the message I expect.

Clive.
Clive Walden
Walden Consulting
Phone: 760-632-5856
Web site: www.clivewalden.com
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Sat Sep 23, 2006 2:30 am    Post subject: Re: EIdClosedSocket and TidcmdTCPServer and Freeze on close Reply with quote



"Clive Walden" <clivew (AT) clivewalden (DOT) com> wrote in message
news:2006922114622.171392@desktop3...

Quote:
I have a problem that my server freezes when I try and set
cmdTCPServer.Active to false when I have clients connected.

That is because your code is wrong. Keep reading.

Quote:
However, it only freezes when I try to add a message to a
memo on the main form in the onDisconnect event.

The code you have shown is not thread-safe. You cannot access the UI of the
main thread from the context of a worker thread. You must Synchronize the
access to that the code accessing the UI is running in the context of the
main thread instead. You are not doing that.

There is another gotcha here. If you use the Synchronize() method of TThread
or TIdSync to access the UI, then you are going to deadlock your code when
shutting down the server. Setting the Active property to false internally
causes the server to wait until all clients have disconnected and all
threads have terminated before then exiting the property setter. If you set
the property in the context of the main thread, then the main thread will be
blocked and unable to process Synchronize() requests. Which in turn will
block the worker threads when they call Syncronize(), so they will be uable
to terminate, and the server will remain blocked.

Quote:
There is no problem when the onDisconnect event is called in the normal
course of events

Yes there is, because you are not accessing the Memo in a safe manner.

Quote:
Here is the relevant code:

Try this code instead:

type
TAddToLogNotify = class(TIdNotify)
protected
FMsg: String;
procedure DoNotify; override;
public
constructor Create(const AMsg: String); reintroduce;
class procedure NotifyMessage(const AMsg: String);
end;

constructor TAddToLogNotify.Create(const AMsg: String);
begin
inherited Create;
FMsg := AMsg;
end;

class procedure TAddToLogNotify.NotifyMessage(AMethod: TIdThreadMethod);
begin
TAddToLogNotify.Create(AMsg).Notify;
end;

procedure TAddToLogNotify.DoNotify;
begin
FAdminFrm.AddToLog(FMsg);
end;


procedure TdmTCPServer.tcpServerDisconnect(AContext: TIdContext);
var
Client : TMyClient;
begin
Client := Pointer(AContext.Data);
AContext.Data := nil;
TAddToLogNotify.NotifyMessage('Disconnecting: ' + Client.Name +' : '
+ TimeTostr(Now) + ' Addr: ' + Client.IPAddress);
FClients.Delete(Client.ListLink);
Client.Free;
CoUnInitialize;
end;


Quote:
When tracing into AddToLog msg does indeed contain
the message I expect.

But you are trying to access the Memo in the context of the worker thread,
not the main thread. All sorts of things can go wrong with that.


Gambit
Back to top
Clive Walden
Guest





PostPosted: Sat Sep 23, 2006 4:05 am    Post subject: Re: EIdClosedSocket and TidcmdTCPServer and Freeze on close Reply with quote



Remy,

Thank you for your usual prompt and informative response.
You are very much appreciated!

I will test out your suggestion ASAP.

I suspected the issue was Synchronization; but was unsure how to address it, especially as neither
the Context nor the IOHandler seemed to have a Synchronize method.

Thanks again.

Clive.
Clive Walden
Walden Consulting
Phone: 760-632-5856
Web site: www.clivewalden.com
Back to top
Clive Walden
Guest





PostPosted: Mon Sep 25, 2006 10:34 pm    Post subject: Re: EIdClosedSocket and TidcmdTCPServer and Freeze on close Reply with quote

A few questions issues now I have tried it<s>.

1. You have a different signature for NotifyMessage in the interface and implementation.
I changed the implementation to match the interface. I hope that was correct.

2. DoNotify.
I had to add the dataModule object instance in front of FAdminFrm.

3. The class method NotifyMessage creates an instance of
TAddToLogNotify; but I see no place where it is freed.
Does the ancestor class take care of that?

Thanks,
Clive.

Clive Walden
Walden Consulting
Phone: 760-632-5856
Web site: www.clivewalden.com
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Tue Sep 26, 2006 2:04 am    Post subject: Re: EIdClosedSocket and TidcmdTCPServer and Freeze on close Reply with quote

"Clive Walden" <clivew (AT) clivewalden (DOT) com> wrote in message
news:2006925103415.043425@desktop3...

Quote:
1. You have a different signature for NotifyMessage in the interface and
implementation.


A typo on my part.

Quote:
I had to add the dataModule object instance in front of FAdminFrm.

You did not say that FAdminFrm was a member of a class, so I did not use it
as one.

Quote:
The class method NotifyMessage creates an instance of
TAddToLogNotify; but I see no place where it is freed.

The TIdNotify class uses an internal thread for triggering notifications.
That thread will free any TIdNotify objects that have been added to its
queue by the TIdNotify.Notify() method.


Gambit
Back to top
Clive Walden
Guest





PostPosted: Tue Sep 26, 2006 2:25 am    Post subject: Re: EIdClosedSocket and TidcmdTCPServer and Freeze on close Reply with quote

Thanks again.

It appears to be working flawlessly.

Clive.
Clive Walden
Walden Consulting
Phone: 760-632-5856
Web site: www.clivewalden.com
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Internet Winsock All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.