Serversocket sembra lento

di il
9 risposte

Serversocket sembra lento

Ciao a tutti.

Ho due applicazioni, su cui girano due comunicazioni, una su CanBus e una su tcpip.

Devo sviluppare una applicazione( o servizio) in stile tcpGateway, cioè tutto quello che arriva da canbus, devo girarlo su tcpip e tutto quello 

che arriva su tcpip devo rigirarlo su canbus.

Sull applicazione client, viene usato il componente Clientsocket che interpreta quello che arriva e lo rimanda al tcpGateway.(oppiure manda direttamente sei messaggi al tcpGateway.

Sul tcpGateway quindi uso il componente serversocket,  sull'evento onclientread manda su canbus sottoforma di array il dato che riceve.

 il codice è il seguente:


procedure TfrmMain.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
const
  cMethodName = 'TfrmMain.ServerSocket1ClientRead';
var
  p: PCANAtom;
  hdrArray: array [0..7] of byte;
  canArray: array [0..15] of byte;
  dataArray: array [0..7] of byte;
  msgArray: array [0..24] of byte;
  msgArrayrec: array [0..24] of byte;
  i: Integer;
  identifier: cardinal;
  pdo, varId: Word;
  hdr: String;
  hexArray: string;
begin
  try
    try
    // Azzeramento dell'array
      FillChar(msgArray, SizeOf(msgArray), 0);
      if Socket.ReceiveBuf (msgArray[0], length (msgArray)) = length (msgArray) then
      begin
        new (p);
        p^ := TCANAtom.Create;

        for i := 0 to 7 do
        begin
          hdrArray[i] := msgArray[i];
        end;

        SetString(hdr, PAnsiChar(@hdrArray[0]), Length(hdrArray));

        if (Trim(Uppercase(hdr)) <> Trim(UpperCase(cMsgHeader1)))  then
        begin
          Exit;
        end;

        for i := 8 to Length(msgArray) - 1 do
        begin
          canArray[i - 8] := msgArray[i];
        end;

        for i := 0 to 7 do
        begin
          dataArray[i] := canArray[8 + i];
        end;

        // IDE
        p^.setIDE(True);
        // PDO
        pdo := ((canArray[1] shl 8) or canArray[0]) shr 7;
        // RTR
        if ((canArray[2] and $1) = $1) then
        begin
          p^.setRTR(True);
        end
        else
        begin
          p^.setRTR(False);
        end;
        // DLC
        p^.setDLC(canArray[6]);
        // Unit and VarId
        varId := (canArray[5] shl 8) or canArray[4];
        p^.setBytes(pdo, canArray[7], varId, canArray[6], dataArray);
        // Confirmation Request
        if ((canArray[3] and $1) = $1) then
        begin
          p^.setConfirmationRequest(True);
        end
        else
        begin
          p^.setConfirmationRequest(False);
        end;
        // Send Message on CAN
        communicationInputList.add(p);
        ourCanInterface.addToOutputList(p);


        hexArray:='';
        for i := 0 to Length(msgArrayrec) - 1 do
        begin
          hexArray := hexArray + '$' + IntToHex(msgArrayrec[i], 2) + ', ';
        end;

        // Rimuovi l'ultima virgola e lo spazio
        Delete(hexArray, Length(hexArray) - 1, 2);


        hexArray:='Ricevuto: '+hexArray;
        Memo2.Lines.Add(hexArray);
      end
      else
      begin
        ourLogger.DbgLog.LogMsg('Unknown message received', eDebugLvlError, cMethodName);
      end;
    except
      on e: Exception do
      begin
        ourLogger.DbgLog.LogMsg('Exception processing received message: ' + e.Message,
                                eDebugLvlError, cMethodName);
      end;
    end;
  finally
    p.Free;
  end;
end;

mentre per mandare su tcp cio che arriva da canbus :


procedure TfrmMain.SendSocketMsg;

const
  cMethodName = 'TfrmMain.SendSocketMsg';
var
  p: PCANAtom;
//  msgArray: TBytes;
  msgArray: array [0..24] of byte;
  hdrArray: TArray<Byte>;
  wrd: Word;
  i, iHdrLen: Integer;
  hexArray: string;
begin
  if not myIsClientConnected then
  begin
    Exit;
  end;
  //
  try
    try
      p := communicationInputList.getFirstOut;
      //SetLength(msgArray, 23);

      hdrArray := TEncoding.UTF8.GetBytes(cMsgHeader1);
      iHdrLen := Length(hdrArray);
      for i := 0 to iHdrLen - 1 do
      begin
        msgArray[i] := hdrArray[i];
      end;

      // PDO
      wrd := p^.getPDO shl 7;
      msgArray[iHdrLen] := byte(wrd);
      msgArray[iHdrLen + 1] := byte(wrd shr 8);
      // RTR
      if p^.getRTR then
      begin
        msgArray[iHdrLen + 2] := 1;
      end
      else
      begin
        msgArray[iHdrLen + 2] := 0;
      end;
      // Reply
      if p^.getConfirmationRequest then
      begin
        msgArray[iHdrLen + 3] := 1;
      end
      else
      begin
        msgArray[iHdrLen + 3] := 0;
      end;
      // VarId
      wrd := p^.getVariableCode;
      msgArray[iHdrLen + 4] := byte(wrd);
      msgArray[iHdrLen + 5] := byte(wrd shr 8);
      // DLC
      msgArray[iHdrLen + 6] := p^.getDLC;
      // Unit
      msgArray[iHdrLen + 7] := p^.getUnitNumber;
      // Data
      p^.dataToByteArray(msgArray, iHdrLen + 8);
      //
//      ServerSocket1.Socket.Connections[0].SendBuf(msgArray[0], Length(msgArray));
      i:=ServerSocket1.Socket.Connections[0].SendBuf(msgArray, Length(msgArray));
for i := 0 to Length(msgArray) - 1 do
  begin
    hexArray := hexArray + '$' + IntToHex(msgArray[i], 2) + ', ';
  end;

  // Rimuovi l'ultima virgola e lo spazio
  Delete(hexArray, Length(hexArray) - 1, 2);

  Memo1.Lines.Add('inviato: (' + hexArray + ')');

      //
      myAnyMessageReadyToSend := True;
    except
      on e: Exception do
      begin
        ourLogger.DbgLog.LogMsg('Exception sending Socket message: ' + e.Message,
                                eDebugLvlError, cMethodName);
      end;
    end;
  finally

  end;
end;

dove la SendSocketMsg dovrebbe scatenarsi ad ogni messaggio che arriva da canbus:

    procedure OnCanManagerMsg(var Msg: TMessage); message WM_CAN_MANAGER;
    
        ourCanInterface := TCANCommunicator.Create(Self.Handle, WM_CAN_MANAGER);
procedure TfrmMain.OnCanManagerMsg(var Msg: TMessage);
begin
  try

        SendSocketMsg;
     
  finally
    Msg.Result := 1;
  end;
end;	

quindi ad ogni messaggio di ourCanInterface  in pratica chiama la sendsocketmsg e fin qui credo che funzioni.

Il problema è che credo che l invio sia decisamente lento in quanto sull applicazione client al ricecvimento dei dati da tcpip fa altre cose 

ma sembra che i messaggi arrivino davvero in maniera ritardata,

da dire che potrebbero arrivare anche 30 messaggi al secondo, ma spero non sia un grosso problema, o perlomeno lo credevo.

Il problema credo sia lato gateway perche il client ora sta andando se configurato per funziona re con una scheda hardware che in pratica fa esattamente la stessa cosa del gateway, ma in queto caso i messaggi arrivano velocemente, quindi credo e spero che il problema sia lato server(tcpgateway), ma non saprei come risolvere data la ‘semplicità’ dell'oggetto serversocket.

9 Risposte

  • Re: Serversocket sembra lento

    17/01/2024 - ziobacco ha scritto:


    Ho due applicazioni, su cui girano due comunicazioni, una su CanBus e una su tcpip.

    Devo sviluppare una applicazione( o servizio) in stile tcpGateway, cioè tutto quello che arriva da canbus, devo girarlo su tcpip e tutto quello 

    che arriva su tcpip devo rigirarlo su canbus.

    Sicuramente lo sai ma esistono dei gateway (hardware) già fatti … costano anche meno di 500 Euro.

    PS - TCP/IP da solo credo che non sia significativo : forse intendi dire Modbus TCP/IP, Ethernet/IP o altro ?

  • Re: Serversocket sembra lento

    17/01/2024 - max.riservo ha scritto:


    17/01/2024 - ziobacco ha scritto:


    Ho due applicazioni, su cui girano due comunicazioni, una su CanBus e una su tcpip.

    Devo sviluppare una applicazione( o servizio) in stile tcpGateway, cioè tutto quello che arriva da canbus, devo girarlo su tcpip e tutto quello 

    che arriva su tcpip devo rigirarlo su canbus.

    Sicuramente lo sai ma esistono dei gateway (hardware) già fatti … costano anche meno di 500 Euro.

    PS - TCP/IP da solo credo che non sia significativo : forse intendi dire Modbus TCP/IP, Ethernet/IP o altro ?

    Gia fatti credo non abbiano le specifiche che servono a me purtroppo, ma non ne conosco.

    comunque intendo da CanBus, della systec https://www.systec-electronic.com/en/products/interfaces-gateways-amp-controls/sysworxx-usb-can-module1  ad un indirizzo ethernet interno in rete su una determinata porta.

    quindi difatto il componente serversocket recuper l indirizzo ip del client che si connette a lui e gli rigira sulla porta 1234 i dati che arrivano dalla comunicazione sul canbus, impacchettati in una certa maniera, perche poi l applicazione client deve ricodificarli…. 

  • Re: Serversocket sembra lento

    A te serve un oggetto che ti converta i segnali elettrici ( e il protocollo) specifici del CanBus in segnali elettrici (e protocollo) gestibili da una connessione TCP/IP : prova a guardare questi https://www.adfweb.com/Home/products/Can_modbus_TCP.asp?frompg=nav1_8

    Se tu converti i registri CanBus (o come si chiamano - è un tipo di bus che non utilizzo) in Modbus TCP/IP (è un protocollo open), trovi ennemila esempi di lettura/scrittura realizzabili con il linguaggio che più ti aggrada (Python, VBA, Delphi ….)

  • Re: Serversocket sembra lento

    Ok ti ringrazio ma non posso prendere e cambiare protocollo cosi a piacimento, io non ho problemi a ricevere i dati dal canbus, ma credo di avere problemi ad inviarli tramite componente socketserver di delphi, magari lo gestisco male, non lo so.

    Magari ci sono componenti piu “efficienti” od affidaili, perchè oltre alla lentezza ho notato ieri che, cosi di botto, smette di funzionare.

  • Re: Serversocket sembra lento

    17/01/2024 - ziobacco ha scritto:


    Il problema è che credo che l invio sia decisamente lento in quanto sull applicazione client al ricecvimento dei dati da tcpip fa altre cose […]

    Vedo che hai inserito dei log su un TMemo: occhio che questa operazione può rallentare molto le performance di qualsiasi algoritmo, perché in generale l'aggiornamento dell'interfaccia utente è una azione che “ruba” CPU, a maggior ragione se si tratta di un TMemo, dove vengono coinvolte anche API di Windows specifiche e diverse da altri controlli.

    18/01/2024 - ziobacco ha scritto:


    Magari ci sono componenti piu “efficienti” od affidaili, perchè oltre alla lentezza ho notato ieri che, cosi di botto, smette di funzionare.

    In effetti, la logica usa molti puntatori e risulta molto farraginosa da leggere.
    Che versione di Delphi stai utilizzando? Ci sono magari componenti più adatti (es. Indy) e classi più semplici per gestire questi buffer, che siano socket o array in memoria (es. TStream e suoi derivati).

  • Re: Serversocket sembra lento

    18/01/2024 - Alka ha scritto:


    Vedo che hai inserito dei log su un TMemo: occhio che questa operazione può rallentare molto le performance di qualsiasi algoritmo, perché in generale l'aggiornamento dell'interfaccia utente è una azione che “ruba” CPU, a maggior ragione se si tratta di un TMemo, dove vengono coinvolte anche API di Windows specifiche e diverse da altri controlli.

    provo allora ad eliminare il tmemo, mi era comodo per verificare l' andamento dei dati, una alternativa piu voloce cosa potrebbe essere? loggare in un file di testo potrbbe essere piu rapido?

    18/01/2024 - Alka ha scritto:


    In effetti, la logica usa molti puntatori e risulta molto farraginosa da leggere.
    Che versione di Delphi stai utilizzando? Ci sono magari componenti più adatti (es. Indy) e classi più semplici per gestire questi buffer, che siano socket o array in memoria (es. TStream e suoi derivati).

    Uso delphi 10.1 berlin version professional.

    Aika perdonami sapresti forse indirizzarmi verso qualche esempio di altri componenti? ho dato un occhio a tidtcpserver (potrebbe fare al caso?) Ma onestamente non ho molto capito come funziona e come dovrei fare per inviare questo buffer che serve a me.

  • Re: Serversocket sembra lento

    18/01/2024 - ziobacco ha scritto:


    provo allora ad eliminare il tmemo, mi era comodo per verificare l' andamento dei dati, una alternativa piu voloce cosa potrebbe essere? loggare in un file di testo potrbbe essere piu rapido?

    Il problema non è essenzialmente dove scrivi il log, ma come: anche un TMemo può andare bene, purché l'azione del logging sia mantenuta asincrona o comunque eseguita in modo molto veloce, ad esempio sfruttando il multithreading, affindando quindi l'informazione a qualcosa che in background se ne occuperà, eventualmente a priorità bassa, mentre il thread che invece gestisce la comunicazione o conversione dei dati continua a lavorare ininterrottamente (salvo per l'operazione di inoltro del messaggio che costituisce la traccia del log).

    18/01/2024 - ziobacco ha scritto:


    Aika perdonami sapresti forse indirizzarmi verso qualche esempio di altri componenti? ho dato un occhio a tidtcpserver (potrebbe fare al caso?) Ma onestamente non ho molto capito come funziona e come dovrei fare per inviare questo buffer che serve a me.

    Fai una ricerca su Google: quei componenti esistono da tantissimo tempo, pur essendo aggiornati progressivamente, quindi la documentazione e gli esempi non mancano. Si tratta solo di usare le giuste parole chiave per ciascuna necessità specifica.

  • Re: Serversocket sembra lento

    Giusto per sfizio ho provato a eliminare proprio il fatto di loggare i messaggi ma la situazione non è che sia cambiata molto.

    tornando sull'uso e la scelta dei componenti, secondo te quindi sarebbe meglio usare qualche altro componente rispetto al serversocket?, il problema potrebbe essere quello? ma che tu sappia ha qualche limite e o limitazione di messaggi e o velocità e o buffer? 

    Sul canbus potrebbero arrivare anche 30 messaggi al secondo, un messaggio ha 24 bytes, non mi pare un grandissimo traffico, ma ho fatto delle prove di invio con un timer, simulando l arrivo di un un messaggio canbus ogni 20 millisecondi, e sul client vedo che cmq non arrivano tutti i pacchetti inviati.

    potrebbe qundi essere un “problema” del componente? non lo conosco ma non mi pare abbia molte opzioni.

    credi risolverei usando TIdTCPServer ? o con un altro?, è piu performante o meglio configurabile?

    grazie mille..

  • Re: Serversocket sembra lento

    18/01/2024 - ziobacco ha scritto:


    Giusto per sfizio ho provato a eliminare proprio il fatto di loggare i messaggi ma la situazione non è che sia cambiata molto.

    Per sapere come procedere, devi anche capire qual è la parte del tuo codice che richiede la maggior parte del tempo e che rappresenta la causa della “lentezza” diagnosticata.

    Ad esempio, puoi usare la classe TStopWatch (vedi questo articolo) per cronometrare le varie fasi parziali e totali di esecuzione del tuo codice, per capire se le tempistiche più lunghe sono riferite a una parte specifica della procedura o riguarda la stessa in tutta la sua interezza.

    18/01/2024 - ziobacco ha scritto:


    tornando sull'uso e la scelta dei componenti, secondo te quindi sarebbe meglio usare qualche altro componente rispetto al serversocket?, il problema potrebbe essere quello? ma che tu sappia ha qualche limite e o limitazione di messaggi e o velocità e o buffer? 

    Per darti questa risposta, dovrei prendere il tuo codice e testarlo: al netto di non avere il tempo, non ho la possibilità di ricreare le tue condizioni né fattivamente posso interpretare e fare “reverse engineering” della procedura.

    Il problema potrebbe essere tutto, ma capirlo vuol dire “misurare” e trarre delle conclusioni dai dati raccolti.

    18/01/2024 - ziobacco ha scritto:


    Sul canbus potrebbero arrivare anche 30 messaggi al secondo, un messaggio ha 24 bytes, non mi pare un grandissimo traffico, ma ho fatto delle prove di invio con un timer, simulando l arrivo di un un messaggio canbus ogni 20 millisecondi, e sul client vedo che cmq non arrivano tutti i pacchetti inviati.

    Ma tu sei sicuro che il codice funzioni e non si perda qualcosa per strada?

    18/01/2024 - ziobacco ha scritto:


    potrebbe qundi essere un “problema” del componente? non lo conosco ma non mi pare abbia molte opzioni.

    credi risolverei usando TIdTCPServer ? o con un altro?, è piu performante o meglio configurabile?

    La proposta di usare un componente alternativo era legato solo al fatto che quello interessato tende a essere un po' anzianotto, benché ancora supportato, e anche perché le alternative possono offrire una API più intuitiva da programmare per raggiungere lo scopo prefissato.

    Quanto alle domande in generale, sul “potrebbe” rispondo sì, ma sul “sicuramente” non posso dire nulla perché - come ho detto sopra - non ho possibilità di testare il tuo codice, l'implementazione usa parecchie strutture dati e non ho la panoramica completa sia dell'input che ricevi e della conversione da fare (ho letto velocemente).

    Io ho suggerito solo strumenti utili, ma il testing, il debugging e la misurazione delle performance devi farla tu, con gli strumenti che sono stati indicati.

    Parlando nello specifico di threading, algoritmi e performance comunque, ci sono una marea di considerazioni da fare: non è impossibile mettere in piedi codice che fa quanto chiedi con poco sforzo, ma quando i volumi e le prestazioni diventano un problema (o un requisito, se c'è un livello minimo richiesto), è necessario approfondire l'argomento e mettere in piedi metodologie e architetture non banali (per lo sviluppatore medio), e quindi purtroppo è necessario anche un pochino di studio, per capire come funzionano le cose e usarle al meglio.

    Ad esempio, su questo tema è consigliatissimo qualche libro dedicato, ad esempio “Delphi High Performance” di Primoz Gabrijelcic, una pubblicazione molto interessante e illuminante (soprattutto per spremere Delphi al massimo e “cavare sangue dalle rape”). :)

    Prova a studiare e approfondire, magari aggredendo un problema alla volta (prima il funzionamento, poi la miglioria alle prestazioni, poi il refactoring, ecc.).

Devi accedere o registrarti per scrivere nel forum
9 risposte