2

I am working on a chat application with Indy 10 in Delphi 7. Now, on the client side, Indy does not have an OnDataReceived or OnRead event, so how can I receive text from the server to the client?

I did try to use the OnWork event with a timer, but my timer is not woking.

Here are the codes for OnWork and TTimer that I used:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if zb_FDataReceived then
  begin
    ShowMessage('Timer triggered!');
    ClientOutput.Lines.Add('Server: ' + zb_FReceivedData);
    zb_FDataReceived := False;
  end;
end;

procedure TForm1.IdTime1Work(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCount: Integer);
begin
  if zb_FDataReceived then
  begin
    ShowMessage('Timer triggered!');
    ClientOutput .Lines.Add('Server: ' + zb_FReceivedData);
    zb_FDataReceived := False;
  end;
end;
1
  • Where and how is zb_FDataReceived set? It's missing in the your code example. Also why would you output 'Timer triggered!' when TForm1.IdTime1Work() cannot be a timer event? If it should execute the same code then you should just call self.Timer1Timer( ASender );. Commented Feb 13, 2024 at 8:11

1 Answer 1

5

Most Indy clients operate synchronously, which is why there is no event in TIdTCPClient when incoming data arrives. The client doesn't read data from the socket until you tell it to read. The OnWork events are meant to be used for status reporting while you are reading/writing data, ie to update a progress bar, etc.

So, to do what you are attempting, you can use a timer, but not in the way you are trying to. On each timer event, you would need to query the socket with a short timeout to see if it has data waiting, and if so then read it. For example:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if Client.IOHandler.InputBufferIsEmpty then
  begin
    Client.IOHandler.CheckForDataOnSource(0);
    Client.IOHandler.CheckForDisconnect;
    if Client.IOHandler.InputBufferIsEmpty then Exit;
  end;
  // read a message from the Client as needed...
end;

That being said, it is usually best to use a separate thread rather than a timer. Have the thread run a loop where each iteration reads from the socket until a new message arrives and then notifies the Main UI thread to display the message. For example:

type
  TReadingThread = class(TThread)
  protected
    FClient: TIdTCPClient;
    procedure Execute; override;
  public
    constructor Create(AClient: TIdTCPClient);
  end;

constructor Create(AClient: TIdTCPClient);
begin
  inherited Create(False);
  FClient := AClient;
end;

procedure TReadingThread.Execute;
begin
  while (not Terminated) and FClient.Connected do
  begin
    // read a message from FClient as needed...
    // update main UI as needed ...
  end;
end;
Client.Connect;
RThread := TReadingThread.Create(Client);
...
Client.Disconnect;
RThread.Terminate;
RThread.WaitFor;
RThread.Free;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.