Solved

Indy TIdAntiFreeze not working?

Posted on 2004-08-17
8
1,247 Views
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);
var
  Client: PClientInfo;
  sTaskType: string;
begin
  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
  LogDebugInfo('Log=Dispatch>>,'+TaskMsgStrList.CommaText);
  AThread.Connection.WriteLn(TaskMsgStrList.CommaText);   // <== just ECHO it
  sTaskType := LowerCase(TaskMsgStrList.Values['TaskType']);
  if sTaskType = 'login' then
    Client.UserName := TaskMsgStrList.Values['UserName'];
end;

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.
0
Comment
Question by:PHenningsen
  • 5
  • 3
8 Comments
 
LVL 3

Expert Comment

by:KyleyHarris
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.
0
 
LVL 3

Expert Comment

by:KyleyHarris
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.
0
 

Author Comment

by:PHenningsen
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?

Thanks,
Phil Henningsen
0
 

Author Comment

by:PHenningsen
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....
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 3

Accepted Solution

by:
KyleyHarris earned 500 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;
end;
     
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.


0
 
LVL 3

Expert Comment

by:KyleyHarris
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.

eg
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.

eg

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

WriteInteger(Length('Hello'));
Write('Hello');


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








0
 

Author Comment

by:PHenningsen
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"?
0
 
LVL 3

Expert Comment

by:KyleyHarris
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 =
begin
  FCS.Acquire; (Local owned critical section)
end;  

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


TMainForm.OnTimer(Sender:TObject);
begin

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

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

end;

0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
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…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

757 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

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now