I am trying to make chat room over Internet with TIdTCP!
When the client send message to server, server will continue to send to other clients, here my code:
Server
var
List: TIdContextList;
Context: TIdContext;
i: Integer;
Msg: String;
Procedure TSForm.SendALL(text: string);
begin
MSG:= Trim(text);
List := Server.Contexts.LockList;
try
for i := 0 to List.Count - 1 do
begin
Context := TIDContext(List[i]);
Context.Connection.IOHandler.WriteLn(UTF8Encode(msg));
end;
finally
Server.Contexts.UnlockList;
end;
end;
procedure TSForm.ServerExecute(AContext: TIdContext);
var m: string;
Begin
m:= acontext.Connection.IOHandler.ReadLn();
begin
SForm.log.Lines.Add(Acontext.Connection.Socket.Binding.PeerIP+' > '+m); //Log is MEMO
SendALL(m);
end;
end;
And Client
type
TReadingThread = class(TThread)
protected
FConn: TIdTCPConnection;
procedure Execute; override;
procedure DoTerminate; override;
public
constructor Create(AConn: TIdTCPConnection); reintroduce;
end;
var readthread: TReadingThread = Nil;
constructor TReadingThread.Create(AConn: TIdTCPConnection);
begin
FConn := AConn;
inherited Create(False);
end;
procedure TReadingThread.Execute;
var
cmd: string;
begin
while not Terminated do
begin
cmd := UTF8ToUnicodeString(FConn.IOHandler.ReadLn());
Trim(cmd);
if cmd <> '' then
begin
CForm.Memo1.Lines.Add(cmd); //Memo1 to show messages
end;
end;
Application.ProcessMessages;
end;
procedure TReadingThread.DoTerminate;
begin
inherited;
end;
procedure TCForm.ClientConnected(Sender: TObject);
begin
readthread:= TReadingThread.Create(Client);
end;
procedure TCForm.ClientDisconnected(Sender: TObject);
begin
if readthread<> nil then
begin
readthread.Terminate;
readthread.WaitFor;
FreeAndNil(readthread);
end;
end;
Everything looks fine, but when Server resend the messages, other clients get it and show in memo normally except The Client which send that message seems freeze, must click to memo to make the text show up!
I don't know what wrong place, hope to get help from you, Thanks!
There are two things wrong with your code:
You are accesing VCL components from second thread. This is generally considered verry bad as it could lead to lots of unforseen problems.
procedure TReadingThread.Execute;
...
CForm.Memo1.Lines.Add(cmd); //Verry bad as you are accesing VCL from another thread
...
Application.ProcessMessages; //This is even worse. I suggest you get rid of this
...
end;
Also get rid of Application.ProcessMessages as this could only cause more problems that it solves not to mention that it greatly affects the programs performance.
So you should use Synchronize command when updating memo. This forces code for updating memo to execute in main thread as all code that is accesing VCL should.
procedure TReadingThread.Execute;
...
Synchronize(
procedure
begin
CForm.Memo1.Lines.Add(cmd);
end;);
...
end;