IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Lazarus Pascal Discussion :

Programme freeze à cause de TTCPBlockSocket [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Membre à l'essai
    Homme Profil pro
    Cyberdocumentaliste
    Inscrit en
    Décembre 2021
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : Cyberdocumentaliste
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2021
    Messages : 11
    Points : 13
    Points
    13
    Par défaut Programme freeze à cause de TTCPBlockSocket
    Bonjour,

    j'ai actuellement plusieurs appareils qui fonctionnent en scpi/ethernet, une alimentation industrielle et un boîtier de mesure. Mon probleme est que si un des appareils est coupé, quand Lazarus envoie la commande, Lazarus plante direct ; le probleme c'est que en cas d'erreur rien ne permet d'arrêter avant que ça plante.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    cmd2:='CONF:VOLT:DC AUTO , (@'+listeTENSIONS+')';
        IP.EcritureIP(IP_KEYSIGHT_VOIE_1,PORT_KEYSIGHT_VOIE_1,cmd2);
     
    function TComIP.ecritureIP(IP, port, Txt_cde : string):String; // cette partie là n'est pas dans le méme form (PCommunicationIP)
    Var sock : TTCPBlockSocket;
      S : string;
    begin
      Sock := TTCPBlockSocket.Create;
      try
        Sock.Connect(IP , port); /////// ca plante ici !!
        Sock.SendString(Txt_cde+#13+#10);
        Sock.CloseSocket;
      finally
        Sock.Free;
      end;
        Result  := s;
    end;  
     
    procedure TBlockSocket.Connect(IP, Port: string);  // cette partie là n'est pas dans le méme form (blcksock)
    var
      Sin: TVarSin;
      b: boolean;
    begin
      SetSin(Sin, IP, Port);
      if FLastError = 0 then
      begin
        if FSocket = INVALID_SOCKET then
          InternalCreateSocket(Sin);
        if FConnectionTimeout > 0 then
        begin
          // connect in non-blocking mode
          b := NonBlockMode;
          NonBlockMode := true;
          SockCheck(synsock.Connect(FSocket, Sin));
          if (FLastError = WSAEINPROGRESS) OR (FLastError = WSAEWOULDBLOCK) then
            if not CanWrite(FConnectionTimeout) then
              FLastError := WSAETIMEDOUT;
          NonBlockMode := b;
        end
        else
          SockCheck(synsock.Connect(FSocket, Sin));
        if FLastError = 0 then
          GetSins;
        FBuffer := '';
        FLastCR := False;
        FLastLF := False;
      end;
      ExceptCheck;
      DoStatus(HR_Connect, IP + ':' + Port);
    end;

  2. #2
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 726
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 726
    Points : 15 126
    Points
    15 126
    Par défaut
    Bonjour,

    Citation Envoyé par leonick12 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    function TComIP.ecritureIP(IP, port, Txt_cde : string):String; // cette partie là n'est pas dans le méme form (PCommunicationIP)
    Var sock : TTCPBlockSocket;
      S : string;
    begin
      Sock := TTCPBlockSocket.Create; 
      try
        Sock.Connect(IP , port); /////// ca plante ici !!
        ...
    Je ne vois aucun test de validité du résultat des actions, c'est pas glop.
    Je ne connais pas du tout ton TTCPBlockSocket, donc à adapter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    begin
      Sock := 0; // si c'est un handle, par exemple
      Sock := TTCPBlockSocket.Create; 
      if Sock = 0 then begin ShowMessage('sock error'); exit; end;
      try
        if not Sock.Connect(IP , port) then begin ShowMessage('connect error'); exit; end;
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  3. #3
    Membre à l'essai
    Homme Profil pro
    Cyberdocumentaliste
    Inscrit en
    Décembre 2021
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : Cyberdocumentaliste
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2021
    Messages : 11
    Points : 13
    Points
    13
    Par défaut
    voila la solution qu'on a trouvé et qui fonctionne correctement, avec ca au moins plus de freeze.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function TComIP.LectureIP(ip, port, text_cmd : string):String;
    Var
      sock : TTCPBlockSocket;
      S : String;
    begin
      Sock := TTCPBlockSocket.Create;
      Sock.RaiseExcept      :=true;
      Sock.ConnectionTimeout:=1200;
      try
        Sock.Connect(ip , port);
        Sock.SendString(text_cmd+#13+#10);
        s := Sock.RecvPacket(7000);
        Sock.CloseSocket;
      except
      on e: ESynapseError do
         begin
        //Showmessage('message');
        Result  := 'erreur';
     
          end;
     
    end;
         Sock.Free;
        Result  := s;
     
    end;

  4. #4
    Membre confirmé

    Homme Profil pro
    Retraité
    Inscrit en
    Avril 2012
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2012
    Messages : 170
    Points : 455
    Points
    455
    Par défaut
    Bonjour,

    Il y a quand même plusieurs choses qui me chiffonnent dans votre code "résolu".

    Le principal est que dans le cas d'une exception, vous n'aurez jamais 'erreur' comme résultat de la fonction, parce que vous lui attribuez la valeur de s ultérieurement !
    En plus, la variable s n'est pas initialisée.
    Enfin, si la création de sock échoue, une exception se produira quand vous voudrez la libérer...
    Et plutôt que de retourner "erreur", pourquoi ne pas ajouter le message d'erreur lui même ?

    Donc, je vous propose :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function TForm1.LectureIP(ip, port, text_cmd : string):String;
    Var
      sock : TTCPBlockSocket;
    begin
      result:= '';                               // initialiser result
      try
        Sock := TTCPBlockSocket.Create;
        Sock.RaiseExcept      :=true;
        Sock.ConnectionTimeout:=1200;
        Sock.Connect(ip , port);
        Sock.SendString(text_cmd+#13+#10);
        result := Sock.RecvPacket(7000);
        Sock.CloseSocket;
      except
        on e: ESynapseError do
        begin
          result:= '';                             // Dans le cas ou l'exception se produit lors de la fermeture du soccket     
          Showmessage('erreur '+e.Message);        // ou ce que vous voulez pour indiquer au programme qu'il y a une erreur
        end;
      end;
      if assigned (Sock) then Sock.Free;           // seulement si sock a bien été créé
    end;
    S'il y a une exception, on a une alerte et le résultat est une chaîne nulle. Si on a une erreur sans exception, on a aussi une chaîne nulle, mais pas d'alerte

    bb84000

  5. #5
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut
    Si la création de sock échoue, ça ne signifie pas pour autant que sock vaille nil puisqu'il n'est pas initialiser non plus
    De plus il n'y aura aucun retour d'information puisque uniquement un type d'exception est traité.

  6. #6
    Membre confirmé

    Homme Profil pro
    Retraité
    Inscrit en
    Avril 2012
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2012
    Messages : 170
    Points : 455
    Points
    455
    Par défaut
    Bonjour,

    Citation Envoyé par Andnotor Voir le message
    Si la création de sock échoue, ça ne signifie pas pour autant que sock vaille nil puisqu'il n'est pas initialiser non plus
    Ce qui me conduit à poser plusieurs questions existentielles à venir !

    Citation Envoyé par Andnotor Voir le message
    De plus il n'y aura aucun retour d'information puisque uniquement un type d'exception est traité.
    oui.

    bb84000

  7. #7
    Membre confirmé

    Homme Profil pro
    Retraité
    Inscrit en
    Avril 2012
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2012
    Messages : 170
    Points : 455
    Points
    455
    Par défaut
    Bonjour,

    Questions induites du précédent message :
    - Un constructeur bien conçu ne devrait-il pas initialiser son objet à nil ?
    - Est-ce qu'il y a une exception toute faite dans Lazarus pour l'échec de création d'un objet, ou doit-on créer sa propre exception ?
    Par exemple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    type EMySockException = Class(Exception);
    ....
    try
        Sock := TTCPBlockSocket.Create;  
        if not assigned(Sock) then raise EMySockException.Create('Sock not assigned');
       .... // et la suite
    except
        ShowMessage(E.Message); 
    end;
    Ou est-ce que je dis une bêtise ?

    bb84000

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut
    Citation Envoyé par bb84000 Voir le message
    - Un constructeur bien conçu ne devrait-il pas initialiser son objet à nil ?
    Le constructeur retourne une adresse, comment pourrait-il savoir ce qu'on en fait ?
    Une variable n'est d'ailleurs pas requise :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    with TMyClass.Create do
    try
      ...
    finally
      Free;
    end;
    Citation Envoyé par bb84000 Voir le message
    - Est-ce qu'il y a une exception toute faite dans Lazarus pour l'échec de création d'un objet, ou doit-on créer sa propre exception ?
    A part un dépassement de capacité (out of memory), ça va dépendre de ce que fait effectivement le constructeur. S'il tente d'ouvrir un fichier, ça pourrait être file not found, access denied, etc. Il n'y a pas qu'une exception possible.

    Quant à protéger la création d'un objet dans un gestionnaire d'exception, je dirais que ce n'est pas si simple que ça et va dépendre de l'applicatif : doit-on interrompre l'action en cours ou renvoyer une valeur par défaut ?
    Dans le premier cas, c'est au niveau le plus élevé de la pile d'appels qu'il faut gérer cela. Dans le deuxième, ça sera immédiatement puisque l'action n'est pas interrompue.

    Ce qu'il faut systématiquement faire est s'assurer qu'il n'y a pas de fuite mémoire en englobant le tout dans un bloc try..finally.

    Il faut bien garder à l'esprit qu'un gestionnaire d'exception n'est pas anodin et affecte les performances de l'application. Si possible il est préférable de tester la validité d'une donnée plutôt que d'attendre une exception, par exemple valeur différente de 0 dans le cas d'une division plutôt que laisser aller jusqu'au EZeroDivide, tester que le fichier existe avant de tenter l'ouverture, etc.

    Créer ses propres exceptions donne une bonne idée de l'endroit où l'erreur est survenue mais dans le gestionnaire lui-même il faut rester le plus générique possible (E:Exception) à moins de pouvoir entreprendre une action précise sur ce type précis. On est alors dans le deuxième cas cité précédemment où l'action n'est pas interrompue.

  9. #9
    Membre confirmé

    Homme Profil pro
    Retraité
    Inscrit en
    Avril 2012
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2012
    Messages : 170
    Points : 455
    Points
    455
    Par défaut
    Bonjour,

    Citation Envoyé par Andnotor Voir le message
    Le constructeur retourne une adresse, comment pourrait-il savoir ce qu'on en fait ?
    Une variable n'est d'ailleurs pas requise :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    with TMyClass.Create do
    try
      ...
    finally
      Free;
    end;
    Mais si la création échoue, est-que Free ne va pas générer une exception ?

    Citation Envoyé par Andnotor Voir le message
    ....
    Si possible il est préférable de tester la validité d'une donnée plutôt que d'attendre une exception, par exemple valeur différente de 0 dans le cas d'une division plutôt que laisser aller jusqu'au EZeroDivide, tester que le fichier existe avant de tenter l'ouverture, etc.
    Oui, nombre non nul, chaîne non nulle, fichier existant... C'est une bonne discipline de programmation.
    Cependant quand j'ai dans une fonction plusieurs lignes risquant de coincer, j'avoue utiliser un try/except global pour simplifier mon code.

    En tout cas, merci (tardif) de tes éclaircissements.

    bb84000

  10. #10
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut
    Citation Envoyé par bb84000 Voir le message
    Mais si la création échoue, est-que Free ne va pas générer une exception ?
    On n'arrivera pas sur cette ligne puisque la création est à l'extérieur du bloc try..finally.

  11. #11
    Membre confirmé

    Homme Profil pro
    Retraité
    Inscrit en
    Avril 2012
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2012
    Messages : 170
    Points : 455
    Points
    455
    Par défaut
    Bonjour,

    Citation Envoyé par Andnotor Voir le message
    On n'arrivera pas sur cette ligne puisque la création est à l'extérieur du bloc try..finally.
    Objection. D'après le wiki :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    begin
      ...
      try
        ...    // code to check
      finally
        ...    // code which should always be executed even in case of error
      end;
      ...
    end;
    Ce qui est logique. Tu peux vérifier avec, par exemple la création d'un label

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      with TLabel.Create(self) do
      try
         Free;                   // ici je le libère, pour simuler une erreur de création
      finally
        ShowMessage('Free');
        Free;
      end;
    end;

    Qu'en penses-tu ?

    bb84000

  12. #12
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut
    Objection rejetée !

    Pour un test correct, soulève effectivement une exception dans un constructeur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    type
      TMyClass = class
      public
        constructor Create;
      end;
     
    constructor TMyClass.Create;
    begin
      raise Exception.Create('Erreur => création annulée');  // Il n'y aura pas de fuite puisque l'allocation est immédiatement libérée sur exception
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      with TMyClass.Create do
      try
        ShowMessage('On ne passe pas sur cette ligne...');
      finally
        ShowMessage('...et celle-ci non plus !');
      end;
    end;

  13. #13
    Membre confirmé

    Homme Profil pro
    Retraité
    Inscrit en
    Avril 2012
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2012
    Messages : 170
    Points : 455
    Points
    455
    Par défaut
    Bonsoir

    OK, mais dans ton exemple, c'est l'ensemble du try..finally...end qui n'est pas exécuté, puisque tu crées une exception avant le try.

    Ce n'est pas ce scenario que j'envisageais, mais celui où la création échouerait sans générer une exception. Est-ce que ce scenario est possible ? Et comment le simuler ? Et je suis vraiment hors sujet !!!

    bb84000

  14. #14
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut
    Citation Envoyé par bb84000 Voir le message
    OK, mais dans ton exemple, c'est l'ensemble du try..finally...end qui n'est pas exécuté, puisque tu crées une exception avant le try.
    Et c'est bien ainsi qu'il faut procéder, il n'y a rien à libérer puisque plus rien n'est alloué dû à la destruction implicite.

    Dans ton exemple il n'y a pas de problème de construction, tu entres logiquement dans le bloc inconditionnel et tu fais un premier Free qui se déroule tout à fait normalement. Ensuite seulement il y a un problème de conception (pour les besoins de ta démo) qui entraîne une violation d'accès sur une deuxième tentative de libération.

    Ta démo est similaire à l'erreur qu'on voit fréquemment d'inclure la création dans le bloc try..finally :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    try
      Create;
    finally
      Free;
    end;
    destruction implicite sur exception dans le constructeur suivi d'une deuxième tentative de destruction.

    Et attention, qui dit destruction (même implicite) dit appel du destructeur qui dans ce cas sera sur une instance partiellement initialisée ! Il peut être nécessaire d'en tenir compte.



    Citation Envoyé par bb84000 Voir le message
    Ce n'est pas ce scenario que j'envisageais, mais celui où la création échouerait sans générer une exception. Est-ce que ce scenario est possible ?
    Réponse simple : non.

    Réponse compliquée : oui mais...
    Les exceptions sont un moyen de protéger le code contre les erreurs pouvant survenir, qu'elles soient générées par le développeur lui-même (raise/assert) ou qu'elles soient des encapsulations des erreurs systèmes.
    Une erreur système non convertie en exception n'en générera évidemment pas mais provoquera purement et simplement le plantage de l'application !

    Ce genre de problème peut survenir lorsque SysUtils n'est pas encore initialisé au démarrage de l'application ou déjà finalisé à sa fermeture, principalement par du code dans les blocs initialization et finalization des unités.

  15. #15
    Membre confirmé

    Homme Profil pro
    Retraité
    Inscrit en
    Avril 2012
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2012
    Messages : 170
    Points : 455
    Points
    455
    Par défaut
    Merci AndNotOr !

    C'est clair pour moi maintenant.

    bb84000

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Programme freeze, aide ajouter thread
    Par deli2025 dans le forum C#
    Réponses: 3
    Dernier message: 22/04/2011, 09h46
  2. [WS 2003] freeze cause VIRUS ou autre chose
    Par djbad dans le forum Windows Serveur
    Réponses: 4
    Dernier message: 21/12/2010, 09h46
  3. Programme Freeze ?
    Par Talimidiusnx dans le forum VB.NET
    Réponses: 5
    Dernier message: 30/10/2010, 23h03
  4. Freeze d'un programme
    Par zoullou dans le forum Général Java
    Réponses: 3
    Dernier message: 17/01/2007, 16h51
  5. Pas d'erreur au debugage mais le programme freeze
    Par bob2356 dans le forum VC++ .NET
    Réponses: 3
    Dernier message: 25/09/2006, 19h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo