Вопрос по – Indy TCP - чтение данных в цикле

2

TCP-сервер непрерывно отправляет фреймы данных каждые 8 мс. Я хочу запрограммировать клиента, способного получать эти фреймы данных. Есть ли какая-нибудь процедура в Indy 9, чтобы узнать, есть ли данные в буфере?

Мои текущие программы следующие (я использую тему):

procedure TThreadRead.Execute;
var
  buffer: array [0..755] of byte;
  //s1: string;
  //i: integer;
begin
  IdTCPClient1.RecvBufferSize:= 756;
  IdTCPClient1.Connect;
  while Terminated = false do
  begin
    if IdTCPClient1.InputBuffer.Size = 0 then
       IdTCPClient1.ReadFromStack(True,0,False);
    while IdTCPClient1.InputBuffer.Size > 0 do
    begin
       ReadBuffer(buffer, FClient.InputBuffer.Size);
       //s1:= '';
       //For i:=0 To Length(buffer)-1 Do
       //  s1:=s1+IntToHex(Ord(buffer[i]),2); //Read values-->global var
       //Form1.Memo1.Text:=s1;
    end;
  end;
end;

Есть ли более эффективное решение для непрерывного чтения данных TCP (например, событие onread в UDP)?

Заранее спасибо.

Ваш Ответ

1   ответ
5

TIdTCPClient не является асинхронным компонентом. Он не сообщает вам, когда поступят данные. Вам нужно использовать Таймер или Поток, чтобы периодически опрашивать сокет для новых данных (TIdUDPServer использует внутренний поток, чтобы вызвать егоOnUDPRead событие), например:

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

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

procedure TForm1.Timer1Timer(Sender: TObject);
var
  s1: string;
begin
  s1 := IdTCPClient1.CurrentReadBuffer;
  ...
end;

С этим сказал,CurrentReadBuffer() как правило, не лучший выбор для использования. Обычно вы делаете что-то более похожее на это:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;

  IdTCPClient1.ReadFromStack(True, 0, False);

  while IdTCPClient1.InputBuffer.Size > 0 do
  begin
    // read one complete frame and process as needed ...
  end;

  Timer1.Enabled := True;
end;

Update: учитывая новую информацию о структуре фрейма и вашем переключении на поток, вы должны сделать это вместо этого:

procedure TThreadRead.Execute;
var
  buffer: array of Byte;
  numbytes: Integer;
begin
  SetLength(buffer, 0);
  IdTCPClient1.Connect;
  try
    while not Terminated do
    begin
      numbytes := StrToInt('$' + IdTCPClient1.ReadString(8)) - 8;
      if numbytes <> Length(buffer) then
        SetLength(buffer, numbytes);
      if numbytes > 0 then
        IdTCPClient1.ReadBuffer(buffer[0], numbytes);
      // process buffer up to numbytes as needed...
    end;
  finally
    IdTCPClient1.Disconnect;
  end;
end;
Error: User Rate Limit Exceeded user1361263
Error: User Rate Limit ExceededInputBufferError: User Rate Limit ExceededReadFromStack()Error: User Rate Limit ExceededInputBufferError: User Rate Limit ExceededInputBufferError: User Rate Limit ExceededInputBufferError: User Rate Limit ExceededReadFromStack()Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededTIdTCPServerError: User Rate Limit ExceededTIdTCPClientError: User Rate Limit Exceeded
Error: User Rate Limit ExceededInputBuffer.SizeError: User Rate Limit ExceededReadFromStack()Error: User Rate Limit ExceededInputBufferError: User Rate Limit ExceededTTimerError: User Rate Limit ExceededSizeError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded user1361263

Похожие вопросы