Pregunta sobre tcp, indy-9, tcpclient, indy – Indy TCP - Leer datos en un bucle

2

Un servidor TCP está enviando marcos de datos continuamente cada 8 ms. Quiero programar un cliente capaz de recibir estos marcos de datos. ¿Hay algún procedimiento en Indy 9 para saber si hay datos disponibles en el búfer?

Mis programas actuales son los siguientes (estoy usando un subproceso):

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;

¿Hay alguna solución más eficiente para leer datos TCP de forma continua (como un evento no leído en UDP)?

Gracias por adelantado.

Tu respuesta

1   la respuesta
5

TIdTCPClient No es un componente asíncrono. No te dice cuándo llegan los datos. Debe usar un temporizador o un hilo para sondear periódicamente el zócalo en busca de nuevos datos (TIdUDPServer utiliza un hilo interno para activar suOnUDPRead evento), por ejemplo:

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;

Con eso dicho,CurrentReadBuffer() Generalmente no es la mejor opción para usar. Típicamente harías algo más como esto en su lugar:

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;

Actualizar: dada la nueva información sobre la estructura del cuadro y su cambio a un hilo, debería hacer esto en su lugar:

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;
Estimado Remy, gracias por ayudarme con este problema. Por último, funcionó correctamente teniendo en cuenta sus consejos. user1361263
La única forma en que aumentar la frecuencia y no cambiar nada más afectaría la capacidad de Indy para leer los marcos es si los marcos se corrompen, por ejemplo, si el dispositivo los solapa, enviando un nuevo marco antes de que se haya enviado el marco anterior. Un rastreador de paquetes, como Wireshark, puede mostrarle qué datos recibe realmente Indy de la red. Eso te mostrará si la corrupción está ocurriendo realmente o no. Remy Lebeau
De hecho, si el tamaño del búfer aumenta, TIdClient lee el búfer de entrada menos veces antes de detener ... user1361263
He actualizado mi respuesta en consecuencia, aunque la anteriorInputBuffer.Size El código de verificación debería haber funcionado bien. Remy Lebeau

Preguntas relacionadas