0
votes

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!

1
Why are you accessing controls directly from the thread?Jerry Dodge
So you think how to add message to memo? Use Timer?Nguyễn Phan Hùng Thuận

1 Answers

3
votes

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;