1
votes

Im writing an Indy chat app, and am wondering if there is a way for the server component to tell the client that there is a string waiting, or even a way for the client to have an "OnExecute" like event. This is what i have now:

server:

procedure TServer.ServerExecute(AContext: TIdContext);
var
  sResponse: string;
  I: Integer;
  list: Tlist;

begin
  List := Server.Contexts.LockList;
  sResponse:= AContext.Connection.Socket.ReadLn;
    try
    for I := 0 to List.Count-1 do
    begin
      try
        TIdContext(List[I]).Connection.IOHandler.WriteLn(sResponse);
      except
      end;
    end;
  finally
    Server.Contexts.UnlockList;
    end;
end;

Client:

procedure TForm1.Button1Click(Sender: TObject);
var
  sMsg : string;
begin
  Client.Socket.WriteLn(edit1.Text);
  sMsg := Client.Socket.ReadLn;
  Memo1.Lines.Add(sMsg);
end;

The problem is when i have 2 or more clients running the messages keep stacking because the button only processes 1 message a time. I'd like a way for the client to wait for messages and when it is triggered it processes those messages, like it does now under the button procedure. I've tried to put the "readln" part under a timer, but that causes some major problems.

Im Using Delphi 2010 and Indy 10

1
I think i've found a great example here 4coder.org/delphi-source-code/290Eszee
Indy uses blocking components. You should put each client on its own thread.Marcus Adams
It is best to have the client do its reading in a separate thread so that it is not blocking the main thread. You could alternatively use a timer that calls the client's IOHandler.CheckForDataOnSource() method with a short timeout and then reads only when the client's IOHandler.InputBuffer is not empty.Remy Lebeau
Also, in your server code, DO NOT lock the Contexts list while you are waiting for data. That prevents clients from connecting/disconnecting. Read the data first, THEN lock the list only when you have something to broadcast to connected clients.Remy Lebeau

1 Answers

1
votes
procedure TForm1.Timer1Timer(Sender: TObject);
var
  sMsg : string;
begin
  IdIOHandlerStack1.CheckForDataOnSource(0);

  sMsg := IdIOHandlerStack1.InputBuffer.AsString;
  if not (sMsg = '') then 
  begin
    Memo1.Lines.Add(IdIOHandlerStack1.InputBuffer.AsString);
    IdIOHandlerStack1.InputBuffer.Clear;
  end;
end;