[2 days left] What’s wrong with your cloud strategy? Learn why multicloud solutions matter with Nimble Storage.Register Now


Indy TIdAntiFreeze not working?

Posted on 2004-08-17
Medium Priority
Last Modified: 2011-10-03
I have an existing client server project that I am converting to use TIdTCPClient and TIdTCPServer.  The "old" version used TClientSocket & TServerSocket with non-blocking sockets.  

The current problem is with the Server.  I have a TIdTCPServer and TIdAntiFreeze components on the main server form.  The Execute method is very simple (right now):

procedure TfmMain.IdTCPServer1Execute(AThread: TIdPeerThread);
  Client: PClientInfo;
  sTaskType: string;
  if (AThread.Terminated) or (not AThread.Connection.Connected) then EXIT;
  Client := PClientInfo(AThread.Data);
  Client.LastAction := Now;
  TaskMsgStrList.CommaText := AThread.Connection.ReadLn;  // <== input to fmMain.TaskMsgStrList
  AThread.Connection.WriteLn(TaskMsgStrList.CommaText);   // <== just ECHO it
  sTaskType := LowerCase(TaskMsgStrList.Values['TaskType']);
  if sTaskType = 'login' then
    Client.UserName := TaskMsgStrList.Values['UserName'];

The problem is that in between communications the Server form is completely unresponsive.  It appears to be "blocked" on the ReadLn statement above.

I thought that that was what the TIdAntiFreeze component was supposed to prevent.
Question by:PHenningsen
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3

Expert Comment

ID: 11827500
Antifreeze is for client use only.

Each Execute is running in the context of AThread, so it does not need antifreeze. Antifreeze basically calls application.processmessages on the client side so that if you use a tcpclient in the mainVCL it will not prevent you cancelling things.

Generally if your code is sitting tight on the readln then it has not received an end of line character in the data.
you may find that the antifreeze is having an adverse reaction in the server code.

Expert Comment

ID: 11827505
also. remember you are in a thread context.

 TaskMsgStrList.CommaText := AThread.Connection.ReadLn;  // <== input to fmMain.TaskMsgStrList

This should be in a syncronize if it is talking to Visual VCL code like a memo etc etc.

Author Comment

ID: 11835864
In all my recent reading about Indy, I never once read that "Antifreeze is for client use only".  But it makes sense.  Anyhow removing it had no effect.

What do you mean by "it has not received an end of line character in the data"?  So far, I'm just using ReadLn & WriteLn.  And I find no place to specify an EOL character.

Further, after the Client sends a msg, the Server responds to my mouse click, but then the Server is still "fubar"...  To the extent that I have to use Task Manager to kill Delphi (yes, Delphi, not the app it was debugging) before continuing.

Re: TaskMsgStrList.CommaText := AThread.Connection.ReadLn.  TaskMsgStrList is intended to be part of "thread local storage".  So my next question is: How do I extend TIdPeerThread to add it?  Where might I find an example of doing that?

Phil Henningsen

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.


Author Comment

ID: 11836071
Further on the Server being "unresponsive":  The Server has a TPageControl with 5 Pages or Tabs.  If I start the Server, and click on each tab BEFORE starting the Client, then all is well.

If I start the Server, then start the Client, then the Server goes unresponsive after the 1st transaction is processed.

Very wierd....

Accepted Solution

KyleyHarris earned 2000 total points
ID: 11836198
It is not weird at all. It is the reason that threads have the synchronize() method for talking to VCL code.
Each gui control has a property Handle:THandle, which binds it to the operating system to receive messages. To save resource. The handle property is only allocated on first use.

ie Memo1.Lines.Add('test')

if this is the first time you've used the memo then that is when the handle is created. if you access a VCL control from within a thread not using synchronize then the Handle is actually created using the thread process as the owner instead of the VCL. from then on your program just won't work properly.

You need to double buffer your server threads using critical sections and intermediary data.

Binding Session Objects.

Not really sure what PClientInfo is?
Typically in the OnConnect event of the server I would create a session object (userdefine) which contains all resources needed by a client session to do its job and
bind it to the thread with the thread Data property. ( I normally go the other way and have a threadsafe list of objects and do the lookup based on threadid)

ie  (sample only, not real)
TUserSession = class(TObject)
  property Thread:TIDPeerThread;
  property UserName:string;
  property Datamodule:string;
  property Privelages:TUserPrivelages

  property ClientInfo:PCLientInfo; // adding your stuff
  property TaskMsgList:TSTringList;
everything this object should be thread safe, and should not talk to the VCL.

in on execute find this object and make use of it.

in the OnDisconnect you free this object.

typically I dont build visual servers. (I have been using indy for 4 years for server based controls)  I build non-visual servers and write information to logs. if i want to see what is happening on the server then I pump out statistics to another client viewer on regular intervals or via messaging systems.

i think the main key here with your issue is the binding of Threaded code into the main VCL. its just a no- no.


Expert Comment

ID: 11836273
One other note on ReadLn and WriteLn.

by using this method of retrieval you are opening your system up to buffer overrun attacks from hackers.

WriteLn('Hi') sends 'Hi'#13#10 over the socket

Readln will get 'Hi'#13#10 and finish the job returning 'Hi' as the result.

if someone conects to your server and does something like

while true do write('a');

Readln will never be able to complete its readln and your server will eventually run out of memory. This is a common past time of people who like to ruin software.
I tend to always use know size parameters.


to send a string 'Hello'
I do something like this


on the other side

ASize := ReadInteger;
if ASize < 1000000 (or some time of validation ) then
  AString := ReadString(ASize);

this is also good from a debugging point of view and results in a faster processing server because it does not have to calculate the length of the data. Essentially it is a PASCAL style string with the size byte first so that you don't need a delimiter at the end.

Hope this helps


Author Comment

ID: 11836636
Thanks so much.  The light is beginning to dawn.

Since the Server's OnConnect procedure was:
procedure TfmMain.IdTCPServer1Connect(AThread: TIdPeerThread);
I pretty much assumed that I was operating in the context of TfmMain.  The culprit was (in ..Connect)
  AThread.Synchronize(RefreshClientListDisplay);  // ie the lack of "synchronize"

Could you expand a bit on what you meant by:
"You need to double buffer your server threads using critical sections and intermediary data."

And, do you mind if I leave this question open for a day before I award you all 500 points & an "A"?

Expert Comment

ID: 11836904
I dont mind about the points at all.

By double buffering I mean... don't talk to the GUI. Make your server non-visual (Dump the controls on a datamodule) Have it so that the threaded server portion adds information to a non-visual control. Create yourself a TCriticalSection (unit SyncObjs) and wrap this around any code which is shared among threads. Then instead of telling the GUI to refresh itself directly, have the GUI examine the server for properties. ie ClientList property, and update itself accordingly. You could use a ttimer or something to keep it simple. The mecansim I uses is thread safe Observation, using a Signal & Slot pattern (To hard to explain here).

I usually think that code should be nicely de-coupled. Make the GUI look at the non-gui, this way it is easy to split the non-gui into a service object.

fuzzy logic code ... :)

FMyTCPServerDM = datamodule with TidTCPServer and all other stuff. with a critical section etc etc.

FMyTCPServerDM.Lock =
  FCS.Acquire; (Local owned critical section)

FMyTCPServerDM.UnLock =
  FCS.Release; (Local owned critical section)


  if FLastClientListUpdateTime <> FMyTCPServerDM.FLastClientUpdateTime then
       Memo1.Lines.Assign(FMyTCPServerDM.ClientList) // Clientlist is a locally owned TStringList;
    FLastClientUpdateTime := FMyTCPServerDM.FLastClientUpdateTime;

//    set FMyTCPServerDM.FLastClientUpdateTime := now; in OnConnect and OnDisconnect;
//    update FMyTCPServerDM..ClientList in OnConnect and OnDisconnect;



Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
Suggested Courses

649 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question