Pytanie w sprawie tcp, tcpclient, indy-9, indy – Indy TCP - odczyt danych w pętli

2

Serwer TCP wysyła ramki danych w sposób ciągły co 8 ms. Chcę zaprogramować klienta w stanie odbierać te ramki danych. Czy w Indy 9 jest jakaś procedura, aby wiedzieć, czy w buforze są dostępne dane?

Moje obecne programy są następujące (używam wątku):

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;

Czy jest jakieś bardziej wydajne rozwiązanie do ciągłego odczytywania danych TCP (jak zdarzenie onread w UDP)?

Z góry dziękuję.

Twoja odpowiedź

1   odpowiedź
5

TIdTCPClient nie jest składnikiem asynchronicznym. Nie informuje o tym, kiedy nadejdą dane. Musisz użyć timera lub wątku, aby okresowo odpytywać gniazdo o nowe dane (TIdUDPServer używa wewnętrznego wątku, aby go uruchomićOnUDPRead zdarzenie), np .:

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;

Z tym powiedziałemCurrentReadBuffer() zazwyczaj nie jest najlepszym wyborem. Zazwyczaj zamiast tego zrobiłbyś coś więcej:

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;

Aktualizacja: podając nowe informacje o strukturze ramki i przełączeniu na wątek, powinieneś to robić zamiast tego:

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;
Nie rozumiem, dlaczego mój klient TCP przestaje odbierać dane user1361263
Próbowałem twojego kodu i jestem w stanie odczytać dane ze stosu, jednak po przeczytaniu kilku ramek danych mój program przestaje odbierać dane (inputBuffer.size staje się zerem ...). Jeśli rozłączę połączenie TCP i uruchomię je ponownie, mogę ponownie odczytać dane ze stosu. user1361263
Odpowiednio zaktualizowałem swoją odpowiedź, choć wcześniejInputBuffer.Size sprawdzanie kodu powinno działać dobrze. Remy Lebeau
Drogi Remy, dziękuję za pomoc w tej sprawie. Wreszcie działało poprawnie, biorąc pod uwagę Twoje rady. user1361263

Powiązane pytania