Pergunta sobre tcp, indy-9, indy, tcpclient – Indy TCP - Lê dados em um loop

2

Um servidor TCP está enviando quadros de dados continuamente a cada 8ms. Eu quero programar um cliente capaz de receber esses quadros de dados. Existe algum procedimento na Indy 9 para saber se há dados disponíveis no buffer?

Meus programas atuais são os seguintes (estou usando um Thread):

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;

Existe alguma solução mais eficiente para ler dados TCP continuamente (como o evento onread no UDP)?

Desde já, obrigado.

Sua resposta

1   a resposta
5

TIdTCPClient não é um componente assíncrono. Não informa quando os dados chegam. Você precisa usar um timer ou um thread para periodicamente pesquisar o soquete para novos dados (TIdUDPServer usa um thread interno para acionar seuOnUDPRead evento), por exemplo:

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;

Com isso dito,CurrentReadBuffer() geralmente não é a melhor escolha para usar. Normalmente, você faria algo mais como isso:

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;

Atualizar: dadas novas informações sobre a estrutura do frame e sua mudança para um thread, você deve fazer isso em vez disso:

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;
Eu atualizei meu primeiro post com o programa atual que estou usando. O servidor TCP está enviando quadros de 756 bytes. Estou recebendo quadros corretos (o cabeçalho é sempre o mesmo). No entanto, depois de receber vários quadros (entre 200 e 1000), recebo um último quadro com tamanho menor que 756 e não recebo mais quadros. Eu preciso desconectar e conectar novamente uma conexão TCP para receber dados novamente. Este erro também acontece usando temporizadores em vez de um Tthread. user1361263
De fato, se o tamanho do buffer é aumentado, o TIdClient lê o buffer de entrada menos vezes antes de parar ... user1361263
Querido Remy, obrigado pela sua resposta. Mas o programa ainda congela ... Mesmo se eu ler menos bytes do buffer de cada vezIdTCPClient1.ReadBuffer(buffer[0], 100) (sabendo que o servidor está enviando 756 bytes cada vez ...) Nenhum erro ocorre ... apenas congela depois de ler vários quadros user1361263
oRecvBufferSize não tem efeito no código que mostrei. É apenas o tamanho do buffer usado paraIndy leitura interna, nãoseu leitura.000002F4 é notação hexadecimal para756, então o que você deve fazer é ler 8 caracteres, convertê-los em um inteiro e depois ler quantos bytes o inteiro disser. Eu atualizei minha resposta para mostrar isso. Remy Lebeau

Perguntas relacionadas