Ajuda Com componete TcpServer e TcpClient

MySQL

Delphi

18/02/2024

Ola amigos, venho aqui pedir a ajuda de vcs mais uma vez,estou com dificuldades sobre esses compontes do titulo.
tenho uma lista de controladoras ,onde cada uma possue seu ip,essas controladoras contem leitores de codigos de barras e cartoes de aproximação,
consigo fazer a comunicação com uma contraladora só, usando os seguintes codigos
TCPClient = TCP
TCPServer = Server
Para configurar o TCPClient e o TCPServer
procedure TFrmGerenciador.conectar;
var
iValorConexao,I :integer;
Bindings : TIdSocketHandle;
begin
  try
   Screen.Cursor := -11;
   TCP.Disconnect;
   TCP.DisconnectNotifyPeer;
   TCP.Host := '192.168.40.8'; 
   TCP.Port := 9760;

   Shape2.Pen.Color := clYellow;

   SERVER.Active := false;
   SERVER.Bindings.Clear;
   Bindings := SERVER.Bindings.Add;
   Bindings.IP := '0.0.0.0';
   Bindings.Port := 9760;
   SERVER.Active := true;
   iValorConexao := 1;
   TCP.Connect;

   btnConectar.Enabled := true;
   Screen.Cursor := 0;
   Shape2.Pen.Color := cllime;

    except on e:Exception do
     begin
      Screen.Cursor := 0;
      btnConectar.Enabled := true;
      Shape2.Pen.Color := clred;
      SERVER.Active := false;
     end;
    end;
end;


No onExecute to tCPServer
procedure TFrmGerenciador.SERVERExecute(AContext: TIdContext);
var
byteBuf : TIdBytes;
Buffer : array [1..1024] of byte;
BufferSec : array [1..1024] of byte;
hexComado : string;
i : integer;
rx, tx : TRxTx;
tamStr : integer;
sComandoSec : string;
begin
   try
        FillChar(Buffer, SizeOf(Buffer), 0);
        AContext.Connection.IOHandler.ReadBytes(byteBuf, 12, false);
        idGlobal.BytesToRaw(byteBuf, Buffer, 12);
        hexComado := '';
        for i := 1 to 12 do
          begin
            hexComado := hexComado + IntToHex(Ord(Buffer[i]), 2);
          end;

        rx := strToRxTx(hexComado);

        if(rx.tamanho > 0) then
         begin
          FillChar(BufferSec, SizeOf(BufferSec), 0);
          AContext.Connection.IOHandler.ReadBytes(byteBuf, rx.tamanho + 1, false);
          idGlobal.BytesToRaw(byteBuf, BufferSec,  rx.tamanho + 1);

           sComandoSec := '';
           for i := 1 to rx.tamanho + 1 do
            begin
              sComandoSec := sComandoSec + IntToHex(Ord(BufferSec[i]), 2);
            end;
            rx.dados := RetZero(sComandoSec, 1024, false);
         end;
        tx := trataComandoPlaca(rx); // AQUI TRATA O COMANDO RECEBIDO DA CONTROLADORA

        hexComado := RxTxtoStr(tx);
        tamStr := length(hexComado) div 2;
        FillChar(Buffer, SizeOf(Buffer), 0);
        for i := 1 to tamStr do
          begin
            Buffer [i + 1] := HexToDec(hexComado[(i*2)+1] + hexComado[(i*2)+2]);
          end;
        byteBuf := Idglobal.RawToBytes(Buffer, tamStr);
        AContext.Connection.IOHandler.Write(byteBuf);

      except on e:Exception do
       begin
               AContext.Connection.DisconnectNotifyPeer;
       end;
   end;
end;


a funçao EnviaComando
function TFrmGerenciador.enviarComando(TX: TRxTx; resposta: Boolean): TRxTx;
var
hexComado, sComandoSec : WideString;
buf, rxBuf : array [1..1024] of byte;
bufSec : array [1..1024] of byte;
tamStr, i : integer;
rx : TRxTx;
byteBuf  : TIdBytes;
begin
   if(not tcp.Connected)  then
   begin
     try
      tcp.Connect();
     except
      exit;
     end;
   end;

  if(not tcp.Connected) then
   exit;
   rx.stx := 0;
   rx.tamanho := 0;
   rx.id_destino := 0;
   rx.id_sub_destino := 0;
   rx.id_fonte := 0;
   rx.comando := '0000';
   rx.dados := '';
   rx.chksum := 0;
   rx.etx := 0;

 try
  FillChar(buf, SizeOf(buf), 0);
 // Comunicando := true;
  //tx.chksum := calculaCK(tx);
  hexComado := RxTxtoStr(tx);
  tamStr := length(hexComado) div 2;
  for i := 0 to tamStr - 1 do
   begin
      buf [i + 1] := HexToDec(hexComado[(i*2)+1] + hexComado[(i*2)+2]);
   end;
  if(tx.tamanho > 0) then
   begin
    byteBuf := Idglobal.RawToBytes(buf, 13 + tx.tamanho);
    tcp.IOHandler.Write(byteBuf);
   end
  else
   begin
    byteBuf := Idglobal.RawToBytes(buf,12);
    tcp.IOHandler.Write(byteBuf);
   end;

  if(resposta = true) then
   begin
    tcp.IOHandler.ReadTimeout := 2000;
    tcp.IOHandler.ReadBytes(byteBuf, 12, false);
    idGlobal.BytesToRaw(byteBuf, rxBuf, 12);

    hexComado := '';
    for i := 1 to 12 do
     begin
       hexComado := hexComado + IntToHex(Ord(rxBuf[i]), 2);
     end;

     rx := strToRxTx(hexComado);
     rx.id_fonte := 0;
     if(rx.tamanho > 0) then
      begin
        FillChar(bufSec, SizeOf(bufSec), 0);
        tcp.IOHandler.ReadTimeout := 2000;
        tcp.IOHandler.ReadBytes(byteBuf, rx.tamanho +1, false);

        idGlobal.BytesToRaw(byteBuf, bufSec, rx.tamanho +1);
         sComandoSec := '';
         for i := 1 to rx.tamanho +1 do
          begin
            sComandoSec := sComandoSec + IntToHex(Ord(bufSec[i]), 2);
          end;
          rx.dados := RetZero(sComandoSec, 1024, false);
      end;
     Result := rx;
   end;
  // Comunicando := false;

   except on e:Exception do
    begin
      rx.stx := 0;
      rx.tamanho := 0;
      rx.id_destino := 0;
      rx.id_sub_destino := 0;
      rx.id_fonte := 0;
      rx.comando := '0000';
      rx.dados := '';
      rx.chksum := 0;
      rx.etx := 0;
      Result := rx;
      tcp.Disconnect;

    end;
 end;
end;

e tem a funçao tratar o comando da controladora que e onde ela vai verificar os codigos de barras de acordo a a base de dados,tratando cada comando da controladora.
Sei que o TcpServer pode receber varios clientes. minhas controladoras estao gravadas em uma tabela, com o numero de ip de cada uma,como posso fazer a comunicaçao com todas elas ao mesmo tempo?para cada controladora irei precisar de um tcpclient? detalhe coloquei mais um tcpclient e configurei ele com outro ip de outra controladora,liguei as duas ao mesmo tempo,conectando elas a um switch,elas se comunicao porem quando eu passo o codigo de barras ela le mas manda o sinal para uma só como se as duas fossem o mesmo ip,se alguem puder me ajuda com um exemplo agradeço.
Alan

Alan

Curtidas 0

Melhor post

Arthur Heinrich

Arthur Heinrich

19/02/2024

Se você conecta às controladoras, para enviar comandos e receber respostas, a sua controladora possui internamente um TCPServer. Você não precisa deste componente.

O que você precisa é de múltiplos TCPClient, um para cada controladora.

Você pode criar um array, instanciar cada elemento dinamicamente e acessar todos usando um "for", por exemplo.
GOSTEI 1

Mais Respostas

Alan

Alan

18/02/2024

Se você conecta às controladoras, para enviar comandos e receber respostas, a sua controladora possui internamente um TCPServer. Você não precisa deste componente.

O que você precisa é de múltiplos TCPClient, um para cada controladora.

Você pode criar um array, instanciar cada elemento dinamicamente e acessar todos usando um "for", por exemplo.


Arthur se não for pedir muito,poderia me dar um exemplo,para estudar?

Tenho um array
Minhas controladoras vão do IP 192.168.40.1 ao 192.168.40.99

IPS : array[1..99] of strings;
GOSTEI 0
Arthur Heinrich

Arthur Heinrich

18/02/2024

Ao invés de arrastar o componente para o seu Form e definir as propriedades em tempo de desenvolvimento, você precisa fazer isso dinamicamente.

var
  sockets : array[1..99] of TTCPClient;
...
for i:=1 to 99 do
  begin
    sockets[i]:=TTCPClient.Create;
    sockets[i].Host := IPS[i]; 
    sockets[i].Port := 9760;
    sockets[i].open;
  end;


Você terá um array contendo 99 componentes TCPClient, cada um conectado ao IP de uma controladora. Tudo deve ser definido da mesma forma como você fez com a classe TCP, que arrastou para o seu form. Mas, neste contexto, será feito para a classe sockets[i].

Ao sair do programa, você pode encerrar a conexão de todos os sockets, com outro loop.

Sempre que um evento ocorre, o método associado ao evento é chamado, passando como parâmetro "Sender" a classe que deu origem ao evento.

Você deve utilizar este parâmetro para interagir com a controladora corretamente.
GOSTEI 1
Alan

Alan

18/02/2024

Ao invés de arrastar o componente para o seu Form e definir as propriedades em tempo de desenvolvimento, você precisa fazer isso dinamicamente.

var
  sockets : array[1..99] of TTCPClient;
...
for i:=1 to 99 do
  begin
    sockets[i]:=TTCPClient.Create;
    sockets[i].Host := IPS[i]; 
    sockets[i].Port := 9760;
    sockets[i].open;
  end;


Você terá um array contendo 99 componentes TCPClient, cada um conectado ao IP de uma controladora. Tudo deve ser definido da mesma forma como você fez com a classe TCP, que arrastou para o seu form. Mas, neste contexto, será feito para a classe sockets[i].

Ao sair do programa, você pode encerrar a conexão de todos os sockets, com outro loop.

Sempre que um evento ocorre, o método associado ao evento é chamado, passando como parâmetro "Sender" a classe que deu origem ao evento.

Você deve utilizar este parâmetro para interagir com a controladora corretamente.


Arthur coloquei esse codigo no botão de conectar do meu form,ele ciar o tcpclient faz a conexão,mas nao tem resposta nenhuma , então fiz ele na funçao EnviarComando ,Criou os sockets TcpClient fez a comunicação mas ele manda a resposta para todas as controladoras conectadas,nao estou sabendo ler em uma controladora e enviar a resposta só pra ela.Criei uma lista de strings so com duas controladoras para testar pq se faço o for com as 99 e alguma nao tiver conectada, nao conecta nenhuma, então fiz com duas so , o codigo ficou assim:
function TFrmGerenciador.enviarComando(TX: TRxTx; resposta: Boolean): TRxTx;
var
hexComado, sComandoSec : WideString;
buf, rxBuf : array [1..1024] of byte;
bufSec : array [1..1024] of byte;
tamStr, i,M : integer;
rx : TRxTx;
byteBuf  : TIdBytes;
 begin
         for m := 1 to 2  do
       begin
        sockets[m] :=TidTCPClient.Create;
        sockets[M].Disconnect;
        sockets[M].DisconnectNotifyPeer;
        sockets[M].Host := ListaDeIps.Strings[m];
        sockets[M].Port := 9760;
        sockets[M].ConnectTimeout := -1;
        sockets[M].IPVersion := Id_IPv4;
        sockets[M].ReadTimeout := -1;
        sockets[M].ReuseSocket := rsFalse;
        sockets[M].Connect;


     if(not sockets[m].Connected)  then
   //if(not tcp.Connected)  then
   begin
     try
       sockets[m].connect();
      //tcp.Connect();
     except
      exit;
     end;
   end;


     if(not sockets[m].Connected) then
  //if(not tcp.Connected) then
   exit;
   rx.stx := 0;
   rx.tamanho := 0;
   rx.id_destino := 0;
   rx.id_sub_destino := 0;
   rx.id_fonte := 0;
   rx.comando := '0000';
   rx.dados := '';
   rx.chksum := 0;
   rx.etx := 0;

 try

  FillChar(buf, SizeOf(buf), 0);
 // Comunicando := true;
  //tx.chksum := calculaCK(tx);
  hexComado := RxTxtoStr(tx);
  tamStr := length(hexComado) div 2;
  for i := 0 to tamStr - 1 do
   begin
      buf [i + 1] := HexToDec(hexComado[(i*2)+1] + hexComado[(i*2)+2]);

   end;
  if(tx.tamanho > 0) then
   begin

    byteBuf := Idglobal.RawToBytes(buf, 13 + tx.tamanho);
    //tcp.IOHandler.Write(byteBuf);
    Sockets[m].IOHandler.Write(byteBuf);

   end
  else
   begin
    byteBuf := Idglobal.RawToBytes(buf,12);
   // tcp.IOHandler.Write(byteBuf);
    Sockets[m].IOHandler.Write(byteBuf);
   end;

  if(resposta = true) then
   begin

    //tcp.IOHandler.ReadTimeout := 2000;
    //tcp.IOHandler.ReadBytes(byteBuf, 12, false);
    Sockets[m].IOHandler.ReadTimeout := 2000;
    Sockets[m].IOHandler.ReadBytes(byteBuf, 12, false);
    idGlobal.BytesToRaw(byteBuf, rxBuf, 12);

    hexComado := '';
    for i := 1 to 12 do
     begin
       hexComado := hexComado + IntToHex(Ord(rxBuf[i]), 2);
     end;

     rx := strToRxTx(hexComado);
     rx.id_fonte := 0;

     if(rx.tamanho > 0) then
      begin
        FillChar(bufSec, SizeOf(bufSec), 0);
       // tcp.IOHandler.ReadTimeout := 2000;
        //tcp.IOHandler.ReadBytes(byteBuf, rx.tamanho +1, false);
        Sockets[m].IOHandler.ReadTimeout := 2000;
        Sockets[m].IOHandler.ReadBytes(byteBuf, rx.tamanho +1, false);

        idGlobal.BytesToRaw(byteBuf, bufSec, rx.tamanho +1);
         sComandoSec := '';
         for i := 1 to rx.tamanho +1 do
          begin
            sComandoSec := sComandoSec + IntToHex(Ord(bufSec[i]), 2);
          end;
          rx.dados := RetZero(sComandoSec, 1024, false);

      end;
     Result := rx;

   end;
   except on e:Exception do
    begin
      rx.stx := 0;
      rx.tamanho := 0;
      rx.id_destino := 0;
      rx.id_sub_destino := 0;
      rx.id_fonte := 0;
      rx.comando := '0000';
      rx.dados := '';
      rx.chksum := 0;
      rx.etx := 0;
      Result := rx;
      //tcp.Disconnect;
      Sockets[m].Disconnect;
    end;
 end;
end;
end;




GOSTEI 0
Alan

Alan

18/02/2024

Ao invés de arrastar o componente para o seu Form e definir as propriedades em tempo de desenvolvimento, você precisa fazer isso dinamicamente.

var
  sockets : array[1..99] of TTCPClient;
...
for i:=1 to 99 do
  begin
    sockets[i]:=TTCPClient.Create;
    sockets[i].Host := IPS[i]; 
    sockets[i].Port := 9760;
    sockets[i].open;
  end;


Você terá um array contendo 99 componentes TCPClient, cada um conectado ao IP de uma controladora. Tudo deve ser definido da mesma forma como você fez com a classe TCP, que arrastou para o seu form. Mas, neste contexto, será feito para a classe sockets[i].

Ao sair do programa, você pode encerrar a conexão de todos os sockets, com outro loop.

Sempre que um evento ocorre, o método associado ao evento é chamado, passando como parâmetro "Sender" a classe que deu origem ao evento.

Você deve utilizar este parâmetro para interagir com a controladora corretamente.


Arthur coloquei esse codigo no botão de conectar do meu form,ele ciar o tcpclient faz a conexão,mas nao tem resposta nenhuma , então fiz ele na funçao EnviarComando ,Criou os sockets TcpClient fez a comunicação mas ele manda a resposta para todas as controladoras conectadas,nao estou sabendo ler em uma controladora e enviar a resposta só pra ela.Criei uma lista de strings so com duas controladoras para testar pq se faço o for com as 99 e alguma nao tiver conectada, nao conecta nenhuma, então fiz com duas so , o codigo ficou assim:
function TFrmGerenciador.enviarComando(TX: TRxTx; resposta: Boolean): TRxTx;
var
hexComado, sComandoSec : WideString;
buf, rxBuf : array [1..1024] of byte;
bufSec : array [1..1024] of byte;
tamStr, i,M : integer;
rx : TRxTx;
byteBuf  : TIdBytes;
 begin
         for m := 1 to 2  do
       begin
        sockets[m] :=TidTCPClient.Create;
        sockets[M].Disconnect;
        sockets[M].DisconnectNotifyPeer;
        sockets[M].Host := ListaDeIps.Strings[m];
        sockets[M].Port := 9760;
        sockets[M].ConnectTimeout := -1;
        sockets[M].IPVersion := Id_IPv4;
        sockets[M].ReadTimeout := -1;
        sockets[M].ReuseSocket := rsFalse;
        sockets[M].Connect;


     if(not sockets[m].Connected)  then
   //if(not tcp.Connected)  then
   begin
     try
       sockets[m].connect();
      //tcp.Connect();
     except
      exit;
     end;
   end;


     if(not sockets[m].Connected) then
  //if(not tcp.Connected) then
   exit;
   rx.stx := 0;
   rx.tamanho := 0;
   rx.id_destino := 0;
   rx.id_sub_destino := 0;
   rx.id_fonte := 0;
   rx.comando := '0000';
   rx.dados := '';
   rx.chksum := 0;
   rx.etx := 0;

 try

  FillChar(buf, SizeOf(buf), 0);
 // Comunicando := true;
  //tx.chksum := calculaCK(tx);
  hexComado := RxTxtoStr(tx);
  tamStr := length(hexComado) div 2;
  for i := 0 to tamStr - 1 do
   begin
      buf [i + 1] := HexToDec(hexComado[(i*2)+1] + hexComado[(i*2)+2]);

   end;
  if(tx.tamanho > 0) then
   begin

    byteBuf := Idglobal.RawToBytes(buf, 13 + tx.tamanho);
    //tcp.IOHandler.Write(byteBuf);
    Sockets[m].IOHandler.Write(byteBuf);

   end
  else
   begin
    byteBuf := Idglobal.RawToBytes(buf,12);
   // tcp.IOHandler.Write(byteBuf);
    Sockets[m].IOHandler.Write(byteBuf);
   end;

  if(resposta = true) then
   begin

    //tcp.IOHandler.ReadTimeout := 2000;
    //tcp.IOHandler.ReadBytes(byteBuf, 12, false);
    Sockets[m].IOHandler.ReadTimeout := 2000;
    Sockets[m].IOHandler.ReadBytes(byteBuf, 12, false);
    idGlobal.BytesToRaw(byteBuf, rxBuf, 12);

    hexComado := '';
    for i := 1 to 12 do
     begin
       hexComado := hexComado + IntToHex(Ord(rxBuf[i]), 2);
     end;

     rx := strToRxTx(hexComado);
     rx.id_fonte := 0;

     if(rx.tamanho > 0) then
      begin
        FillChar(bufSec, SizeOf(bufSec), 0);
       // tcp.IOHandler.ReadTimeout := 2000;
        //tcp.IOHandler.ReadBytes(byteBuf, rx.tamanho +1, false);
        Sockets[m].IOHandler.ReadTimeout := 2000;
        Sockets[m].IOHandler.ReadBytes(byteBuf, rx.tamanho +1, false);

        idGlobal.BytesToRaw(byteBuf, bufSec, rx.tamanho +1);
         sComandoSec := '';
         for i := 1 to rx.tamanho +1 do
          begin
            sComandoSec := sComandoSec + IntToHex(Ord(bufSec[i]), 2);
          end;
          rx.dados := RetZero(sComandoSec, 1024, false);

      end;
     Result := rx;

   end;
   except on e:Exception do
    begin
      rx.stx := 0;
      rx.tamanho := 0;
      rx.id_destino := 0;
      rx.id_sub_destino := 0;
      rx.id_fonte := 0;
      rx.comando := '0000';
      rx.dados := '';
      rx.chksum := 0;
      rx.etx := 0;
      Result := rx;
      //tcp.Disconnect;
      Sockets[m].Disconnect;
    end;
 end;
end;
end;







Tenho uma função que trata o comando recebido pela controladora, nele fiz um case dos comandos ,ficou mais ou menos assim,dei uma abreviada para não ficar muito grande o codigo.
function TFrmGerenciador.trataComandoPlaca(RX: TRxTx): TRxTx;  /////
  var
rxStr : string;
receber  :shortString;
comando : string;
tx : TRxTx;
i, n,j : Integer;
sTemplate : WideString;
sTemplate2: WideString;
buf : array of Byte;
card64 : Cardinal;
Mifare : String;
strSerial: String;
txx, rxx : TRxTx;
 sTemp, sTemp2, sComando: string;
 num_bytes,l  :Integer;
begin
  try
     tx.stx := 2;
      tx.chksum := 0;
      tx.comando := '0101';
      tx.dados := RetZero('', 1024, true);
      tx.etx :=  3;
      tx.id_destino :=0;
      tx.id_fonte := 0;
      tx.id_sub_destino := 0;
      tx.tamanho := 0;
     //verifica ck
      rxStr := RxTxtoStr(RX);
      comando := RX.comando;
     // card64 := HexToCardinal(InverteHexa(Copy (rx.dados,3,8), 8));
      //id := HexToDec(Copy (rx.dados,1,2));
      card64 := HexToCardinal(InverteHexa(Copy ( rx.dados,1,8), 8));

      if(HexToDEC(comando) = $0000)then
      begin
      tx.comando := '0102';
      Result := tx;
      exit;
      end;
    case HexToDEC(comando) of
  $0701: begin  // LEITOR DE APROXIMAÇÃO.
            
       // VERIFICO SE O REGISTRO EXISTE NA TABELA COM AS CONDIÇÕES "IF" 
              SE O NUMERO DO INGRESSO EXISTE NA TABELA, SALVA EM OUTRA TABELA E  MANDA MENSAGEM PARA O DISPLAY DA CONTROLADORA
            // MANDA MENSAGEM PARA O DISPLAY
            sTemp := '';
            sTemp2 := '';
            sComando := '';
            sTemp := ' >> ENTRADA << ';
            num_bytes := length(sTemp);
            sTemp2 := '';
            for l := 1 to num_bytes do
              begin
                sTemp2 := sTemp2 + CharStrToHexStr(sTemp[l]);
              end;

            SComando := SComando + RetZero(sTemp2, 32, false);

            sTemp := '>> PERMITIDA <<';
            num_bytes := length(sTemp);
            sTemp2 := '';
            for l := 1 to num_bytes do
              begin
                sTemp2 := sTemp2 + CharStrToHexStr(sTemp[l]);
              end;

            SComando := SComando + RetZero(sTemp2, 32, false);
            SComando := SComando + IntToHex(StrToInt('10'), 2);
          // AQUI FAZ A LIBERAÇÃO NA CONTROLADORA MANDANDO O COMANDO 
          tx.stx := 2;
          tx.chksum := 0;
          tx.comando :=  '080F' ;// COMANDO PARA MANDAR MENSAGEM PARA ACONTROLADORA
          tx.dados := RetZero(SComando, 512, false);
          tx.etx :=  3;
          tx.id_destino := 1;
          tx.id_fonte := 9;
          tx.id_sub_destino := 8;
          tx.tamanho := length(SComando) div 2;
          rx := enviarComando(tx, true);

          // LIBERA O ACESSO.
          tx.stx := 2;
          tx.chksum := 0;
          tx.comando :=  '080B' ; //COMANDO DE LIBERAÇÃO
          tx.dados := RetZero(SComando, 512, false);
          tx.etx :=  3;
          tx.id_destino := 1;
          tx.id_fonte := 9;
          tx.id_sub_destino := 8;
          tx.tamanho := length(SComando) div 2;
          rx := enviarComando(tx, true);      
          end;   
      
GOSTEI 0
Alan

Alan

18/02/2024

   //VERIFICA SE O INGRESSO JÁ FOI ULTILIZADO,SE SIM BLOQUEIA E MANDA MENSAGEM PARA A CONTROLADORA E SALVA NA TABELA        
         
       //MENSAGEM QUE VAI ENVIAR PARA A CONTROLADORA
          sTemp := '';
          sTemp2 := '';
          sComando := '';
          sTemp := '>>JA UTILIZADO<<';
          num_bytes := length(sTemp);
          sTemp2 := '';
          for l := 1 to num_bytes do
            begin
              sTemp2 := sTemp2 + CharStrToHexStr(sTemp[l]);
            end;

          SComando := SComando + RetZero(sTemp2, 32, false);

          sTemp := dateTimeToStr(dm.IngressosTabledata_entrou.value);
          num_bytes := length(sTemp);
          sTemp2 := '';
          for l := 1 to num_bytes do
            begin
              sTemp2 := sTemp2 + CharStrToHexStr(sTemp[l]);
            end;

          SComando := SComando + RetZero(sTemp2, 32, false);
          SComando := SComando + IntToHex(StrToInt('10'), 2);

          tx.stx := 2;
          tx.chksum := 0;
          tx.comando := '080F'; //COMANDO PARA MANDAR MENSAGEM PARA ACONTROLADORA
          tx.dados := RetZero(SComando, 512, false);
          tx.etx :=  3;
          tx.id_destino := 1;
          tx.id_fonte := 9;
          tx.id_sub_destino := 8;
          tx.tamanho := length(SComando) div 2;
          rx := enviarComando(tx, true);        
        end;
 // VERIFICA SE O SETOR É PERMITIDO
         if (dm.Ingressostable.RecordCount <> 0) and (dm.IngressosTablePermitido.value = 0) then
         begin
          //emensagem1.Text := INTTOSTR(CARD64);
         dm.IngressosEvento.Open;
         dm.IngressosEvento.Append;
         dm.IngressosEventoIdentificacao.value :=   IntToStr(card64);
         dm.IngressosEventoDescricao.Value := 'SETOR INCORRETO';
         dm.IngressosEventoTipo.Value := 'BLOQUEIO';
         dm.IngressosEventoId_setor.Value := dm.IngressosTableId_setor.Value;
         dm.IngressosEventoid_ingresso.Value := dm.ingressostableid.value;
         dm.IngressosEventoId_controladora.Value := rx.id_fonte;
         dm.IngressosEvento.post;

          sTemp := '';
          sTemp2 := '';
          sComando := '';
          sTemp := 'SETOR INCORRETO';
          num_bytes := length(sTemp);
          sTemp2 := '';
          for l := 1 to num_bytes do
            begin
              sTemp2 := sTemp2 + CharStrToHexStr(sTemp[l]);
            end;

          SComando := SComando + RetZero(sTemp2, 32, false);

          sTemp :=  dm.IngressosTableSetor.value;
          num_bytes := length(sTemp);
          sTemp2 := '';
          for l := 1 to num_bytes do
            begin
              sTemp2 := sTemp2 + CharStrToHexStr(sTemp[l]);
            end;

          SComando := SComando + RetZero(sTemp2, 32, false);
          SComando := SComando + IntToHex(StrToInt('10'), 2);

          tx.stx := 2;
          tx.chksum := 0;
          tx.comando := '080F';
          tx.dados := RetZero(SComando, 512, false);
          tx.etx :=  3;
          tx.id_destino := 1;
          tx.id_fonte := 9;
          tx.id_sub_destino := 8;
          tx.tamanho := length(SComando) div 2;
         rx := enviarComando(tx, true);       
         end;
      //VERIFICO SE O INGRESSO EXISTE, SE NAO ,SALVA NA TABELA E MANDA A MENSSAGEM 

        sTemp := '';
        sTemp2 := '';
        sComando := '';
        sTemp := '>>INGRESSO NAO<<';
        num_bytes := length(sTemp);
        sTemp2 := '';
        for l := 1 to num_bytes do
          begin
            sTemp2 := sTemp2 + CharStrToHexStr(sTemp[l]);
          end;
        SComando := SComando + RetZero(sTemp2, 32, false);
        sTemp := '>>>CADASTRADO<<<';
        num_bytes := length(sTemp);
        sTemp2 := '';
        for l := 1 to num_bytes do
          begin
            sTemp2 := sTemp2 + CharStrToHexStr(sTemp[l]);
          end;
        SComando := SComando + RetZero(sTemp2, 32, false);
        SComando := SComando + IntToHex(StrToInt('10'), 2);

        tx.stx := 2;
        tx.chksum := 0;
        tx.comando := '080F'; COMANDO PARA MANDAR MENSAGEM PARA ACONTROLADORA
        tx.dados := RetZero(SComando, 512, false);
        tx.etx :=  3;
        tx.id_destino := 1;
        tx.id_fonte := 9;
        tx.id_sub_destino := 8;
        tx.tamanho := length(SComando) div 2;
        rx := enviarComando(tx, true);
         end;
       end;
      end;
$0A01 : begin // COMANDO QUANDO RODA O BRAÇO DA CATRACA (CONTROLADORA)
// SALVA O REGISTRO NA TABELA, FAZ UM UPDATE PARA O INGRESSO NAO SER MAIS VALIDO.
         dm.Ingressostable.Open;
         dm.Ingressostable.Filtered := false;
         dm.Ingressostable.Filter := 'identificacao =' + IDENTIFIC;
         dm.Ingressostable.Filtered := true;

         if dm.Ingressostable.RecordCount > 0  then
         if (Dm.IngressosTablehexadecimal.Value = 0)  then
          begin
          dm.IngressosEvento.Open;
          dm.IngressosEvento.Append;
          dm.IngressosEventoId_controladora.Value := rx.id_fonte;
          dm.IngressosEventoId_setor.Value := dm.IngressosTableId_setor.Value;
          dm.IngressosEventoId_ingresso.Value := dm.IngressosTableid.AsInteger;
          dm.IngressosEventoIdentificacao.Value := IDENTIFIC;
          dm.IngressosEventoDescricao.Value := 'ENTRADA CONCLUIDA';
          dm.IngressosEventoTipo.value := 'ENTRADA';
          dm.IngressosEvento.Post;

         //FAZ UM UPDATE PARA DESVALIDAR.
         dm.IngressosTable.sql.Clear;
         dm.IngressosTable.SQL.Add('update ingressos SET Valido = "1" WHERE Valido = "0"  AND Identificacao = :pident');
         dm.IngressosTable.ParamByName('pident').value := IDENTIFIC;;
         Dm.IngressosTable.ExecSQL;

        // ABRE A TABELA DE INGRESSOS
         dm.IngressosTable.close;
         dm.IngressosTable.SQL.Clear;
         dm.IngressosTable.SQL.Add('select *from ingressos') ;
         dm.IngressosTable.open;
         end;      
         END;

 $0A31 : begin //COMANDO QUANDO O BRAÇO DA CATRACA(CONTROLADORA )NAO E RODADO
         //SÓ INSERE NA TABELA
          dm.IngressosEvento.Open;
          dm.IngressosEvento.Append;
          dm.IngressosEventoId_setor.Value := dm.IngressosTableId_setor.Value;
          dm.IngressosEventoId_controladora.Value := rx.id_fonte;
          dm.IngressosEventoId_ingresso.Value := dm.IngressosTableid.AsInteger;
          dm.IngressosEventoIdentificacao.Value :=  IDENTIFIC;
          dm.IngressosEventoDescricao.Value := 'ENTRADA NÃO CONCLUÍDA';
          dm.IngressosEventoTipo.value :='NENHUM';
          dm.IngressosEvento.Post;       
       end;
     end;

o rx.id_fonte é o id da placa , nao sei se estou errando algo aqui
GOSTEI 0
Arthur Heinrich

Arthur Heinrich

18/02/2024

Você está pensando de forma síncrona, onde envia um comando e aguarda pela resposta. Comunicações de rede funcionam melhor quando utilizamos uma lógica assíncrona, onde você envia um comando e, eventualmente e em algum momento, a resposta chega, podendo não chegar. Enquanto isso, seu programa segue fazendo outras atividades, até que uma mensagem chegue de uma das interfaces. Neste momento, seu código será interrompido para tratar a mensagem recebida.

Um componente do tipo TCPSocket possui eventos (event handlers), que precisam ser implementados e associados à classe, no momento da criação/conexão. Como exemplo, seguem os eventos da classe TClientSocket:

OnConnect: Occurs on client sockets just after the connection to the server is opened.
OnConnecting: Occurs for a client socket after the server socket has been located, but before the connection is established.
OnDisconnect: Occurs just before a client socket closes the connection to a server socket.
OnError: Occurs when the socket fails in making, using, or shutting down a connection.
OnLookup: Occurs when a client socket is about to look up the server socket with which it wants to connect.
OnRead: Occurs when a client socket should read information from the socket connection.
OnWrite: Occurs when a client socket should write information to the socket connection.

Sempre que o server envia uma resposta, o evento OnRead é disparado, para que você trate a mensagem recebida de um socket em particular.

No link https://stackoverflow.com/questions/25733064/error-with-sockets-in-delphi existe um exemplo, onde são criados e atribuídos os event handlers.

A procedure/método usado para ler os dados do socket (no exemplo) é esta:

procedure ClientRead(Self: Pointer; Sender: TObject; Socket: TCustomWinSocket);
var
  len: Integer;
  Buf: PByte;
begin
  len := Socket.ReceiveLength;
  if len <= 0 then Exit;
  GetMem(Buf, len);
  try
    len := Socket.ReceiveBuf(Buf^, len);
    if len <= 0 then Exit;
    // use data as needed...
  finally
    FreeMem(Buf);
  end;
end;


Repare que, ao ler os dados, ele utiliza o socket passado para o event handler (parâmetro Socket). Este é o socket que recebeu a mensagem e é a partir desta classe que você precisa ler os dados. Você não precisa adivinhar qual dos sockets que você mantém no array está interagindo com você.

É importante lembrar que, quando um pacote de rede chega, ele pode conter dados parciais. Você precisa de um mecanismo para tratar os dados recebidos e perceber se chegaram múltiplas mensagens ou se a última/única mensagem que chegou está completa.

Isto tem a ver com o protocolo utilizado pela aplicação ou, no seu caso, as suas interfaces.

A beleza da orientação a objetos é justamente o fato de você poder criar uma classe a partir de outra. Você pode criar uma classe sua TInterfaceSocket, que herde as características do socket padrão, implementando os eventos (event handlers internamente), no evento OnCreate ou através do Constructor, de forma que cada classe se comporte como um pequeno programa, que interage com apenas uma interface. Nela, pode haver um buffer onde você vai concatenando os dados recebidos e, à medida que uma resposta chega completa, você a trata e descarta do buffer a parte já tratada.

Ao adotar a abordagem orientada a objetos, você torna seu problema mais simples.
GOSTEI 1
Alan

Alan

18/02/2024

Você está pensando de forma síncrona, onde envia um comando e aguarda pela resposta. Comunicações de rede funcionam melhor quando utilizamos uma lógica assíncrona, onde você envia um comando e, eventualmente e em algum momento, a resposta chega, podendo não chegar. Enquanto isso, seu programa segue fazendo outras atividades, até que uma mensagem chegue de uma das interfaces. Neste momento, seu código será interrompido para tratar a mensagem recebida.

Um componente do tipo TCPSocket possui eventos (event handlers), que precisam ser implementados e associados à classe, no momento da criação/conexão. Como exemplo, seguem os eventos da classe TClientSocket:

OnConnect: Occurs on client sockets just after the connection to the server is opened.
OnConnecting: Occurs for a client socket after the server socket has been located, but before the connection is established.
OnDisconnect: Occurs just before a client socket closes the connection to a server socket.
OnError: Occurs when the socket fails in making, using, or shutting down a connection.
OnLookup: Occurs when a client socket is about to look up the server socket with which it wants to connect.
OnRead: Occurs when a client socket should read information from the socket connection.
OnWrite: Occurs when a client socket should write information to the socket connection.

Sempre que o server envia uma resposta, o evento OnRead é disparado, para que você trate a mensagem recebida de um socket em particular.

No link https://stackoverflow.com/questions/25733064/error-with-sockets-in-delphi existe um exemplo, onde são criados e atribuídos os event handlers.

A procedure/método usado para ler os dados do socket (no exemplo) é esta:

procedure ClientRead(Self: Pointer; Sender: TObject; Socket: TCustomWinSocket);
var
  len: Integer;
  Buf: PByte;
begin
  len := Socket.ReceiveLength;
  if len <= 0 then Exit;
  GetMem(Buf, len);
  try
    len := Socket.ReceiveBuf(Buf^, len);
    if len <= 0 then Exit;
    // use data as needed...
  finally
    FreeMem(Buf);
  end;
end;


Repare que, ao ler os dados, ele utiliza o socket passado para o event handler (parâmetro Socket). Este é o socket que recebeu a mensagem e é a partir desta classe que você precisa ler os dados. Você não precisa adivinhar qual dos sockets que você mantém no array está interagindo com você.

É importante lembrar que, quando um pacote de rede chega, ele pode conter dados parciais. Você precisa de um mecanismo para tratar os dados recebidos e perceber se chegaram múltiplas mensagens ou se a última/única mensagem que chegou está completa.

Isto tem a ver com o protocolo utilizado pela aplicação ou, no seu caso, as suas interfaces.

A beleza da orientação a objetos é justamente o fato de você poder criar uma classe a partir de outra. Você pode criar uma classe sua TInterfaceSocket, que herde as características do socket padrão, implementando os eventos (event handlers internamente), no evento OnCreate ou através do Constructor, de forma que cada classe se comporte como um pequeno programa, que interage com apenas uma interface. Nela, pode haver um buffer onde você vai concatenando os dados recebidos e, à medida que uma resposta chega completa, você a trata e descarta do buffer a parte já tratada.

Ao adotar a abordagem orientada a objetos, você torna seu problema mais simples.

Cara para falar a verdade estou quebrando a cabeça a dias com isso,esses codigos que te mandei é uns fontes que o fabricante da controladora me passou ,só dei uma modificada ,mas estou apanhando muito nesses componentes,para ser sincero ja nem sei mais se vou ser capaz de conseguir isso, minha ideia e levar ao maximo ate onde eu conseguir ,e depois ver se acho alguem para finalizar para mim.Voce disse que esta com muito serviço e nao tera atenção q um cliente precisa,tem alguma ideia de quando voce ficaria livre,ou tem algum contato pra me indicar,ou pode me indicar algum curso sobre esses componentes?
GOSTEI 0
Arthur Heinrich

Arthur Heinrich

18/02/2024

Eu trabalho full time dedicado para uma empresa e também não sou nenhum especialista em sockets.

Olhando as rotinas que você encaminhou, a comunicação ocorre em binário. A rorina fica convertendo os dados binários em hexadecimal e vice-versa. Tem várias classes que parecem ser do fornecedor das interfaces. É meio complicado. Tem que ler a documentação e implementar.

Dá trabalho mesmo.

Antes de implementar para todas as interfaces. Você precisa aprender a lidar com uma só, até entender como enviar comandos e receber a resposta. Somente depois de estar familiarizado com o protocolo e com as classes do fabricante é que você deve tentar tratar múltiplas interfaces ao mesmo tempo. Do contrário, você mistura duas coisas que não sabe fazer muito bem e ficará perdido, sem saber onde errou.
GOSTEI 1
Alan

Alan

18/02/2024

Eu trabalho full time dedicado para uma empresa e também não sou nenhum especialista em sockets.

Olhando as rotinas que você encaminhou, a comunicação ocorre em binário. A rorina fica convertendo os dados binários em hexadecimal e vice-versa. Tem várias classes que parecem ser do fornecedor das interfaces. É meio complicado. Tem que ler a documentação e implementar.

Dá trabalho mesmo.

Antes de implementar para todas as interfaces. Você precisa aprender a lidar com uma só, até entender como enviar comandos e receber a resposta. Somente depois de estar familiarizado com o protocolo e com as classes do fabricante é que você deve tentar tratar múltiplas interfaces ao mesmo tempo. Do contrário, você mistura duas coisas que não sabe fazer muito bem e ficará perdido, sem saber onde errou.
É então com uma controladora só funciona perfeito,mas quando conecto mais de uma,não importa por qual controladora vc lê o ingresso ela manda mensagem para todas ,só pra salvar na tabela q ela salva com id certo de cada uma, mas vou fuçar mais um pouco e ver no que dá ,se não der em nada vou ter que procurar alguém que faça para mim ,mas uma vez obrigado.
GOSTEI 0
POSTAR