Как я могу ждать строку с сервера с IdTCPClient? - PullRequest
2 голосов
/ 03 ноября 2011

У меня проблема с IdTelnet (indy 10.1). Я не могу прочитать данные с сервера в режиме Unicode. и теперь я хочу написать терминал Telnet с IdTCPClient.

Сервер иногда отправляет одну строку, а иногда все больше и больше строк. Но между отправкой нет фиксированного времени.

Теперь моя проблема в том, что когда я должен читать данные из InBuffer.

Или когда я должен использовать функцию ReadLn для чтения данных с сервера, сколько раз я должен запускать ReadLn?

1 Ответ

7 голосов
/ 03 ноября 2011

TIdTelnet - многопоточный компонент.Он имеет внутренний поток, который непрерывно читает данные из сокета, вызывая событие TIdTelnet.OnDataAvailable всякий раз, когда доступен буфер данных.

TIdTelnet является потомком TIdTCPClient.Посмотрите в исходном файле IdTelnet.pas, чтобы увидеть, как это реализовано.Вы можете сделать что-то подобное в своем собственном коде, вызывая TIdIOHandler.ReadLn() в своем собственном потоке, например:

type
  TMyThread = class(TThread)
  private
    FConn: TIdTCPConnection;
  protected
    procedure Execute; override;
  public
    constructor Create(AConn: TIdTCPConnection); reintroduce;
  end;

constructor TMyThread.Create(AConn: TIdTCPConnection);
begin
  inherited Create(False);
  FConn := AConn;
end;

procedure TMyThread.Execute;
var
  S: String;
begin
  while not Terminated do
  begin
    S := FConn.IOHandler.ReadLn(...);
    ...
  end;
end;

var
  Thread: TMyThread = nil;

procedure TForm1.ConnectButtonClick(Sender: TObject);
begin
  IdTCPClient1.Connect;
  try
    Thread := TMyThread.Create(IdTCPClient1);
  except
    IdTCPClient1.Disconnect;
    raise;
  end;
end;

procedure TForm1.DisconnectButtonClick(Sender: TObject);
begin
  if Assigned(Thread) then Thread.Terminate;
  try
    IdTCPClient1.Disconnect;
  finally
    if Assigned(Thread) then
    begin
      Thread.WaitFor;
      FreeAndNil(Thread);
    end;
  end;
end;

Если вы не хотите использовать поток, вы можете вместо этого использовать таймер.Чтобы убедиться, что ваш поток таймера (например, основной поток) не заблокирован без необходимости, используйте метод TIdIOHandler.CheckForDataOnSource() с небольшим таймаутом, когда TIdIOHandler.InputBuffer пуст, перед тем как вызывать TIdIOHandler.ReadLn() только при наличии данных, например:

procedure TForm1.ConnectButtonClick(Sender: TObject);
begin
  IdTCPClient1.Connect;
  ReadTimer.Enabled := True;
end;

procedure TForm1.DisconnectButtonClick(Sender: TObject);
begin
  ReadTimer.Enabled := False;
  IdTCPClient1.Disconnect;
end;

procedure TForm1.ReadTimerElapsed(Sender: TObject);
var
  S: String;
begin
  if IdTCPClient1.IOHandler.InputBufferIsEmpty then
  begin
    IdTCPClient1.IOHandler.CheckForDataOnSource(10);
    if IdTCPClient1.IOHandler.InputBufferIsEmpty then Exit;
  end;
  S := IdTCPClient1.IOHandler.ReadLn(...);
  ...
end;
...