Newsgroups : Borland : borland.public.delphi.internet.winsock : 2008 Feb : Re: Reply Code is not valid

www.cryer.info
Managed Newsgroup Archive

Re: Reply Code is not valid

Subject:Re: Reply Code is not valid
Posted by:"Remy Lebeau (TeamB)" (no.spam@no.spam.com)
Date:Thu, 14 Feb 2008 12:29:30

"Kendrick" <kkendrick@harbornet.com> wrote in message
news:47b49c10$1@newsgroups.borland.com...

> OK - it is from CodeGear but if it is wrong it is wrong.

CodeGear did not write any of the Indy demos.

> I believe it was to acheive a type of multithreading.

TIdCmdTCPServer is already multi-threaded.  But the demo (if it did indeed
use window messages - you did not indicate which demo you are looking at) is
trying to prevent the server's own threads from blocking, I guess.  They are
better ways to accomplish what you are attempting.

> In my case I will only want to handle one connection at a time.
> Are you recommending moving the call to SendClientMessage
> directly into the command handler event or just use writeln?

Since you only allow one connection at a time, there is no point in
delegating the workload to the main thread at all.  For example:

    procedure TMyServer.CommandRUN(ASender: TIdCommand);
    begin
        try
            MainForm.SendClientMessage(ASender, ASender.Params[0]);
        except
            on E: Exception do
            begin
                PostDBugMsg('TMyServer.CommandRUN ' + E.ClassName + ':' +
E.Message, ASender.Context.Connection.Socket.Binding.Handle);
                raise;
            end;
        end;
    end;

    type
        TLogSync = class(TIdSync)
        protected
            fMsg: String;
            procedure DoSynchronize; override;
        public
            class procedure Add(const AMsg: String);
        end;

    class procedure TLogSync.Add(const AMsg: String);
    begin
        with Create do
        try
            fMsg := AMsg;
            Synchronize;
        finally
            Free;
        end;
    end;

    procedure TLogSync.DoSynchronize;
    begin
        frmMain.mLog.Lines.Insert(0, fMsg);
    end;

    procedure TfmMain.SendClientMessage(ACommand: TIdCommand; const aStr:
string = ''; const showTime: boolean = False; const log: boolean = True);
    var
        s: string;
        h: TIdStackSocketHandle;
    begin
        h := ASender.Context.Connection.Socket.Binding.Handle;

        s := IntToStr(h) + ': ' + aStr;
        if showTime then s := s + ':' + TimeToStr(Now);

        ASender.Reply.SetReply(200, s);
        ASender.SendReply;

        if log then
        begin
            s := aStr;
            if showTime then s := TimeToStr(Now) + ':' + s ;
            s := s +  ' (' + IntToStr(h) + ')';
            TLogSync.Add(s);
        end;
    end;

> The main reason I've used the seperation is there is no telling
> the amount of time between the receiving and acknowledging
> of a command and acquiring the result set in response to the
> command, and then then sending the triger to the client to
> instigate the request for the result set.

Your code is not set up very well to handle that scenerio on either end.
You are going to have to redesign your code to not use SendCmd() on the
client end at all.  Have the client use just WriteLn() to send commands to
the server, and then not wait for a reply right away.  Use a separate
timer/thread/whatever to poll the connection periodically for inbound
packets asynchronously.  You will then need to include some kind of
identifier in your packet data so your client can know whether a given
inbound string is a reply to an earlier client-issued command, or is a new
server-issued trigger, and then act accordingly.  You will also have to
implement a queuing system on the server so that replies and triggers cannot
be transmitted at the same time and thus corrupt each other.


Gambit

Replies:

In response to:

www.cryer.info
Managed Newsgroup Archive