Newsgroups : Borland : borland.public.delphi.internet.winsock : 2007 Apr : Re: Delphi 7 & Indy 10 TidCmdTCPServer OnCommand Event

www.cryer.info
Managed Newsgroup Archive

Re: Delphi 7 & Indy 10 TidCmdTCPServer OnCommand Event

Subject:Re: Delphi 7 & Indy 10 TidCmdTCPServer OnCommand Event
Posted by:"Remy Lebeau (TeamB)" (no.spam@no.spam.com)
Date:Wed, 11 Apr 2007 10:02:21

"Codeman II" <thegentleman@webmail.co.za> wrote in message
news:461cb584@newsgroups.borland.com...

>       ResponseString.Clear;
>       ParamsList.Clear;
>       SenderIP := ...;

Where are those variables declared?  Are they being shared amongst
multiple threads?

>       ASender.Context.Binding.PeerIP;

TIdContext does not have a Binding property.  You have to access it
through the Connection instead:

    SenderIP := ASender.Context.Connection.Socket.Binding.PeerIP;

>       ACommand := ASender.CommandHandler.Command + ' ';
>       For X := 0 to ASender.Params.Count - 1 do ACommand := ACommand
+
> ASender.Params.Strings[X] + ' ';
>       ACommand := Trim(ACommand);

You could simply use the RawLine property instead:

    ACommand := ASender.RawLine;

> fADirection, fALine, fAIPAddress are public variables to
> hold values for the SynchronizeMethod() method
> which update the log file display using a TRichEdit component.

Then they are being shared amongst multiple threads.  You are not
protecting them adequately enough.  You should write a new class so
that they can be local to each call to SynchronizeMethod() (which is
itself static so you don't need an instance of TIdSync unless you
derive from it) without effecting other threads.

>       For X := 0 to ComputerIPS.Count - 1 do
>       begin
>         If ComputerIPS.Strings[X] <> SenderIP then

Where is ComputerIPS declared?  That looks like another shared list
that is not being protected correctly.  You don't need to maintain
your own list of IPs anyway.  Just use the TIdCmdTCPServers built-in
Contexts list instead.

> fACommand, fAHost holds values for the SynchronizeMethod()
> to broadcast command to the rest of the clients.

More variables that need to be local to the thread context that is
calling SynchronizeMethod().  Don't use shared variables.

With that said, try the following instead (untested):

    type
        TLogSync = class(TIdSync)
        private
            fDirection: String;
            fLine: String;
            fIPAddress: String;
            procedure DoSynchronize; override;
        public
            procedure Write(const ADirection, ALine, AIPAddress:
String);
        end;

    procedure TLogSync.DoSynchronize;
    begin
        // write fDirection, fLine, and fIPAddress to TRichEdit as
needed...
    end;

    procedure TLogSync.Write(const ADirection, ALine, AIPAddress:
String);
    begin
        fDirection := ADirection;
        fLine := ALine;
        fIPAddress := AIPAddress;
        Synchronize;
    end;


    procedure TfrmMainServer.IdCommandCmdFlagUpdateCommand(ASender:
TIdCommand);
    var
        Log: TLogSync;
        LLocalIP, LSenderIP: String;
        LContext: TIdContext;
        LServer: TIdCmdTCPServer;
        LList: TIdList;
        I: Integer;
    begin
        Log := TLogSync.Create;
        try
            try
                LLocalIP :=
ASender.Context.Connection.Socket.Binding.IP;
                LSenderIP :=
ASender.Context.Connection.Socket.Binding.PeerIP;

                Log.Write(dirIN, ASender.CommandHandler.Command,
LSenderIP);

                ASender.Response.Add('FlagUpdate Received.');
                Log.Write(dirOUT, ASender.Response.Text, LLocalIP);

                LServer :=
TIdCmdTCPServer(TIdCommandHandlers(ASender.CommandHandler.Collection).
Base);
                // or just use your form's TIdCmdTCPServer variable
directly, it is ok here

                LList := LServer.Contexts.LockList;
                try
                    for I := 0 to List.Count - 1 do
                    begin
                        try
                            LContext := TIdContext(List[I]);
                            if LContext <> ASender.Context then
                            begin
                                // send ACommand to LContext as
needed...

LContext.Connection.IOHandler.WriteLn(ASender.RawLine);

                                Log.Write(dirOUT, 'Broadcasting to: '
+ LContext.Connection.Socket.Binding.PeerIP, LLocalIP);
                            end;
                        except
                        end;
                    end;
                    Log.Write(dirNone, '', '');
                finally
                    LServer.Contexts.UnlockList;
                end;
            except
                on E: EIdException do
                begin
                    Log.Write(dirError, 'Indy Error: ' + E.Message,
LLocalIP + ' --> ' + LSenderIP);
                end;
                on E: Exception do
                begin
                    Log.Write(dirError; 'VCL Error: ' + E.Message,
LLocalIP + ' --> ' + LSenderIP);
                end;
            end;
        finally
            Log.Free;
        end;
    end;


Gambit

Replies:

In response to:

www.cryer.info
Managed Newsgroup Archive