Newsgroups : Borland : borland.public.delphi.internet.winsock : 2007 Apr : 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