Newsgroups : Borland : borland.public.delphi.internet.winsock : 2007 Mar : Re: How to set the listen port for the TIdTCPServer?

www.cryer.info
Managed Newsgroup Archive

Re: How to set the listen port for the TIdTCPServer?

Subject:Re: How to set the listen port for the TIdTCPServer?
Posted by:"Bo Berglund" (bo.berglu..@telia.com)
Date:Mon, 26 Mar 2007 23:53:56

On Sun, 25 Mar 2007 15:38:20 -0800, "Remy Lebeau \(TeamB\)"
<no.spam@no.spam.com> wrote:

>
>"Bo Berglund" <bo.berglund@telia.com> wrote in message
>news:5jrd035l3e93che03n679pnl8ibpg0g2ct@4ax.com...
>
>>   while not AThread.Terminated and AThread.Connection.Connected do
>
>Get rid of that line.  You should not be looping at all.  TIdTCPServer
>triggers the OnExecute event handler inside an internal loop of its
>own.

OK, I will, it was a fluke from misreading the examples. I am still
thinking of having an eternal loop in the OnConnect in order to grab
the handle to the client so I can send commands to it during the time
it stays connected.
I don't want to do that in the main line of the code so just setting a
local variable to the AThread object and later use that to send data
to the client seems to me to use the thread of the main app to execute
the Connection.Write method and thus suffer from the blocking
behaviour. Instead I plan to put outgoing data into a list that is
read in the internal loop in OnConnect and is written by the mainline
code.

>
>> It seems like the server is stripping off the terminator (</msg>
>> from the returned data.
>
>It is.  That is how ReadLn() is designed to operate
>
>> Could this be changed so that I will receive the complete string?
>
>The simpliest way is to append the terminator to the end of the data
>that is returned, ie:
>
>    procedure TTool.srvCommandExecute(AThread: TIdPeerThread);
>    var
>        sRecData: String;
>    begin
>        sRecData := AThread.Connection.ReadLn('</msg>', 2000);
>        if sRecData <> '' then
>            AddCmdResponse(sRecData + '</msg>');
>    end;
>
>Alternatively, I normally would suggest using WaitFor() instead of
>ReadLn(), ie:
>
>    procedure TTool.srvCommandExecute(AThread: TIdPeerThread);
>    var
>        sRecData: string;
>    begin
>        sRecData := AThread.Connection.WaitFor('</msg>');
>        AddCmdResponse(sRecData);
>    end;
>
>However, WaitFor() is buggy in Indy 9.  If there is pending data in
>the socket after the desired message, the extra data gets included in
>the result, which will mess up your communication.  This was fixed in
>Indy 10, ie:
>
>    procedure TTool.srvCommandExecute(AContext: TIdContext);
>    var
>        sRecData: string;
>    begin
>        sRecData := AThread.Connection.IOHandler.WaitFor('</msg>',
>True, True);
>        AddCmdResponse(sRecData);
>    end;
>
>But for Indy 9, you would have to call ReadFromStack() and then
>manually scan the InputBuffer, ie:
>
>    procedure TTool.srvCommandExecute(AThread: TIdPeerThread);
>    var
>        sRecData: String;
>        iPos: Integer;
>    begin
>        repeat
>            AThread.Connection.ReadFromStack(True, 100, False);
>            iPos := MemoryPos('</msg>',
>PChar(AThread.Connection.InputBuffer.Memory),
>AThread.Connection.InputBuffer.Size);
>        until iPos <> 0;
>        sRecData := AThread.Connection.ReadString(iPos+5);
>        AddCmdResponse(sRecData);
>    end;

Thanks for the explanation, I'll look into this tomorrow at work.

One final thing:
When looking at the server example for Indy9 I noticed that they have
dropped a TIdThreadMgrDefault component on the form and connected it
to the TIdTCPServer. What is the purpose of this?
If I also need to do the same (but not on a form, since I am creating
everything in code in my own object), do I need one such object per
server (I am using two servers)???

/Bo

Replies:

In response to:

www.cryer.info
Managed Newsgroup Archive