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

C Discussion :

Vérifier si un programme est ouvert et l'utiliser


Sujet :

C

  1. #61
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    Je viens de modifier mon code : il compile... Mais ne marche pas encore

    Je dois me préparer pour le boulot...

    J'ai failli sortir l'expression "j'ai d'autres chats à fouetter"
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

  2. #62
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    En l'état ça marche... Ou presque !

    En effet au démarrage du serveur, j'ai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     ./a.out
    serveur absent : le programme devient serveur: No such file or directory
    Après, lors de l'ouverture d'un client, j'ai bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Connexion entrante ... affectée au slot 0.
    Après, la fermeture du serveur n'est pas repérée par les clients. Le programme se ferme quand j'envoie un message au serveur mort :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ ./a.out 
    30 : numéro 0 a rejoint le canal.
     
    Message à envoyer au serveur (fin pour arrêter le serveur) : fin
    2 : 97
    Vérification OK
    Continuer ? (o/n) : o
     
    Message à envoyer au serveur (fin pour arrêter le serveur) : rtfdx
    [troumad@localhost][~/Documents/socket]
    Alors que j'aurais aimé avoir mon message affiché par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    		    printf("Le serveur a fermé la connexion\n");
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

  3. #63
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    Je viens de comprendre pourquoi le "No such file or directory" : je tente une écoute sans savoir s'il y a un serveur. Comme il n'y en a pas, il n'y a pas le fichier SERVER_PATH => c'est un affichage d'avertissement que je gère en interne en lançant le serveur.

    Mainetant, la suite...
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

  4. #64
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 368
    Points : 23 620
    Points
    23 620
    Par défaut
    C'est à ça que sert perror() : cette fonction affiche le message que tu lui passes en argument suivi d'un deux-point et d'un espace, puis du message correspondant à l'erreur dont le code est dans errno.

    Donc en général, on écrit dans perror() ce que l'on est (ou était) en train de faire au moment où l'on appelle la fonction, et on la laisse donner d'elle même la raison de l'échec. C'est le principe.

  5. #65
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    J'avais oublié cette fonction que je n'utilise pas souvent... En fait, ce n'est pas une erreur pour mon programme ! Ça détecte juste l'absence de serveur.

    Maintetant, j'ai trouver ce qui ne va pas, mais je ne comprends pas pourquoi ça réagit comme ça ici. C'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     rc = send(sd, buffer, strlen(buffer), 0);
    qui plante : le programme sort sur cette ligne quand il n'y a pas de serveur à l'écoute, comme si j'avais mis return. Je ne passe même pas par la détection d'erreur qui arrive juste après ! Pourquoi ?

    Je comprends ça et mon programme est bon pour partir en exemple non ?
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

  6. #66
    Expert éminent sénior

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 603
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 603
    Points : 17 913
    Points
    17 913
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par troumad Voir le message
    Maintetant, j'ai trouver ce qui ne va pas, mais je ne comprends pas pourquoi ça réagit comme ça ici. C'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     rc = send(sd, buffer, strlen(buffer), 0);
    qui plante : le programme sort sur cette ligne quand il n'y a pas de serveur à l'écoute, comme si j'avais mis return. Je ne passe même pas par la détection d'erreur qui arrive juste après ! Pourquoi ?
    Parce que send, receive, read, et write ont des exit internes en cas d'erreur..

    D'où l'utilisaton de poll en cas d'utilisation de ces fonctions pour avoir des programmes propres qui ne plantent pas..
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  7. #67
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par troumad Voir le message
    Maintetant, j'ai trouver ce qui ne va pas, mais je ne comprends pas pourquoi ça réagit comme ça ici. C'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     rc = send(sd, buffer, strlen(buffer), 0);
    qui plante : le programme sort sur cette ligne quand il n'y a pas de serveur à l'écoute, comme si j'avais mis return. Je ne passe même pas par la détection d'erreur qui arrive juste après ! Pourquoi ?
    Ça fonctionne chez moi. Tu utilises quel système (et quel noyau) ?

    Je comprends ça et mon programme est bon pour partir en exemple non ?
    Enlève quand même les fflush(stdin) !

    Citation Envoyé par souviron34 Voir le message
    Parce que send, receive, read, et write ont des exit internes en cas d'erreur.. D'où l'utilisaton de poll en cas d'utilisation de ces fonctions pour avoir des programmes propres qui ne plantent pas..
    Ça, pour le coup, ça me surprend beaucoup. J'ai déjà rencontré ça dans des bibliothèques tierces (Sybase, par exemple), et ça m'avait mis de mauvaise humeur, mais un exit() carrément dans le noyau, c'est sauvage quand même. Sur quel système as-tu déjà rencontré cela ?

  8. #68
    Expert éminent sénior

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 603
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 603
    Points : 17 913
    Points
    17 913
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Ça, pour le coup, ça me surprend beaucoup. J'ai déjà rencontré ça dans des bibliothèques tierces (Sybase, par exemple), et ça m'avait mis de mauvaise humeur, mais un exit() carrément dans le noyau, c'est sauvage quand même. Sur quel système as-tu déjà rencontré cela ?

    Pardon ce n'est pas un exit mais un crash


    HPUX et linux (RedHat en tous cas jusqu'à 6).

    Plus testé après car mis les poll avant chaque écriture/lecture..

    Mais un tour du côté du code source de la stdlib donnera les précisions, ou un essai bête et méchant comme Troumad l'a fait..

    Faire un write ou un read alors que le client en face s'est cassé la gueule ou n'est plus là entraîne un crash..

    Pour les send/receive je ne sais pas mais je suppose même chose d'après ce qu'il dit...


    D'où mes multiples avertissements dans la section réseaux sur le fait que il y a très peu de serveurs/clients mettant en place une gestion propre réellement des pertes de connexions (que ce soit dans la détection des signaux ou pour les écritures), et mon insistance sur l'utilisation des polls, que ce soit afin de vérifier le fait que c'est toujours UP avant de communiquer ou que ce soit pour éviter les crashs)..

    Faire un serveur/client 100% fiable est assez long, mais si on se fait une petite biblothèque de gestion générale c'est assez simple, car une fois fait ça s'applique partout..


    NOTE : si le client (ou le serveur) crashe via un SEGFAULT par exemple, ça ne génère pas de signaux cross-noeuds, et donc pas de changement d'état du socket.. Cela peut être aussi le cas en intra-plateforme... Un SIGHUP ou autre ne sera donc pas généré et donc pas détectable...
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  9. #69
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    — Tu as plusieurs fflush(stdin) dans ta partie client et qui ne servent à rien : tu ne pourras jamais vider le buffer d'entrée de cette façon
    Tu fais comment pour le vider proprement alors ?

    Sinon, je suis sous Mageia 64 bits avec un noyau 2.6.38.6-desktop-1.mga pour cette histoire de sortie de send...
    Et c'est quoi cette histoire de poll ?

    Sinon, dans mon cas, je vérifie la présence du fichier SERVER_PATH . Non ?
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

  10. #70
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par troumad Voir le message
    Maintetant, j'ai trouver ce qui ne va pas, mais je ne comprends pas pourquoi ça réagit comme ça ici. C'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     rc = send(sd, buffer, strlen(buffer), 0);
    qui plante : le programme sort sur cette ligne quand il n'y a pas de serveur à l'écoute, comme si j'avais mis return. Je ne passe même pas par la détection d'erreur qui arrive juste après ! Pourquoi ?
    Citation Envoyé par souviron34 Voir le message
    Faire un write ou un read alors que le client en face s'est cassé la gueule ou n'est plus là entraîne un crash..
    D'accord. Je n'avais pas compris qu'il se connectait d'abord puis tuait le serveur entre temps. Dans ce cas-là, ce n'est pas un crash au sens accidentel du terme mais un SIGPIPE qu'il reçoit. Cela se confirme en lançant le client avec un débogueur, même sans les symboles.

    Dans ce cas, c'est normal que le programme prenne fin sans autre forme de notification si celui-ci ne prend pas explicitement en charge le cas de figure. C'est à cela que sert le signal en question…

    NOTE : si le client (ou le serveur) crashe via un SEGFAULT par exemple, ça ne génère pas de signaux cross-noeuds, et donc pas de changement d'état du socket.. Cela peut être aussi le cas en intra-plateforme... Un SIGHUP ou autre ne sera donc pas généré et donc pas détectable...
    Non, effectivement, mais c'est normal : le signal émis ne concerne que le processus destinataire et n'a de sens que pour lui. Cela dit, la mort du processus concerné devrait provoquer la fermeture de ses sockets par le système et, de là, provoquer des SIGPIPE chez les processus qui y étaient toujours reliés.

    Ce qui est surprenant, c'est que cela ne soit pas immédiat, même avec un socket de type SOCK_STREAM. Cela dit, un sock_stream est littéralement un socket orienté flux. Cela n'implique pas forcément qu'il s'agisse d'une liaison orientée connexion.

    Citation Envoyé par troumad Voir le message
    Tu fais comment pour le vider proprement alors ?
    Ce n'est même pas une question de vider « proprement » ou pas le buffer d'entrée. C'est simplement que ça ne marchera pas du tout.

    On rappelle qu'il faut comprendre « flush » dans le sens de « tirer la chasse ». Ça veut dire que fflush sert à provoquer l'envoi immédiat des données en attente dans un buffer vers leur destination programmée. Donc, dans le cas de stdout, tout ce qui est en attente est envoyé vers la sortie, par défaut vers l'écran.

    Dans le cas de stdin, la destination en question, c'est le processus. Si celui-ci fait fflush(stdin), il provoque l'envoi immédiat des données en attente… vers lui-même ! Donc, s'il ne les lit pas, il n'y a aucune raison pour que ça bouge.

    D'une certaine manière, le fait que le buffer de stdout se retrouve vide après l'opération peut presque être considéré comme un effet de bord. fflush() sert donc à vider un buffer de sortie comme on vide un stock, mais certainement pas à l'effacer.

    La manière la plus propre, je pense, consiste à passer temporairement le descripteur de fichier en mode non-bloquant avec fcntl(), puis à aller remplir un buffer d'une taille arbitraire avec fread() et continuer tant que la lecture remplit entièrement le buffer. Alors, on réinitialise les flags d'erreurs de stdin avec clearerr() et on rétablit les attributs d'états initiaux avec fcntl().

    Ça veut aussi dire qu'il n'y a pas de moyen 100 % langage C de le faire à coup sûr. Il faut passer par la programmation système au moins pour passer en mode non bloquant. Au passage, je pense que cette entrée de la F.A.Q. est fausse, car la routine en question s'arrête soit au premier retour à la ligne et il peut y avoir des données après, soit sur un EOF qui n'arrivera jamais si l'entrée standard est une console.

  11. #71
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    D'accord. Je n'avais pas compris qu'il se connectait d'abord puis tuait le serveur entre temps. Dans ce cas-là, ce n'est pas un crash au sens accidentel du terme mais un SIGPIPE qu'il reçoit. Cela se confirme en lançant le client avec un débogueur, même sans les symboles.
    C'est peut-être un autre client qui l'a tué !
    Je fais quoi alors pour vérifier si le serveur est mort ? Le serveur envoie un message à tout ces clients pour dire qu'il est mort ?

    Citation Envoyé par Obsidian Voir le message
    Ce n'est même pas une question de vider « proprement » ou pas le buffer d'entrée. C'est simplement que ça ne marchera pas du tout.

    On rappelle qu'il faut comprendre « flush » dans le sens de « tirer la chasse ». Ça veut dire que fflush sert à provoquer l'envoi immédiat des données en attente dans un buffer vers leur destination programmée. Donc, dans le cas de stdout, tout ce qui est en attente est envoyé vers la sortie, par défaut vers l'écran.

    Dans le cas de stdin, la destination en question, c'est le processus. Si celui-ci fait fflush(stdin), il provoque l'envoi immédiat des données en attente… vers lui-même ! Donc, s'il ne les lit pas, il n'y a aucune raison pour que ça bouge.

    D'une certaine manière, le fait que le buffer de stdout se retrouve vide après l'opération peut presque être considéré comme un effet de bord. fflush() sert donc à vider un buffer de sortie comme on vide un stock, mais certainement pas à l'effacer.

    La manière la plus propre, je pense, consiste à passer temporairement le descripteur de fichier en mode non-bloquant avec fcntl(), puis à aller remplir un buffer d'une taille arbitraire avec fread() et continuer tant que la lecture remplit entièrement le buffer. Alors, on réinitialise les flags d'erreurs de stdin avec clearerr() et on rétablit les attributs d'états initiaux avec fcntl().

    Ça veut aussi dire qu'il n'y a pas de moyen 100 % langage C de le faire à coup sûr. Il faut passer par la programmation système au moins pour passer en mode non bloquant. Au passage, je pense que cette entrée de la F.A.Q. est fausse, car la routine en question s'arrête soit au premier retour à la ligne et il peut y avoir des données après, soit sur un EOF qui n'arrivera jamais si l'entrée standard est une console.
    Je suis assez intéressé par ce point qui n'a rien à voir avec le sujet traité ici
    Certes, là, je récupère toute la chaîne entrée sans me poser des questions sur le formatage.
    Pour la récupération du o/n (fin du client), j'avais déjà une boucle pour vider le buffer jusqu'au signal "entrée".

    nb : je ne peux plus modifier mon code source car ça fait trop longtemps qu'il a été posté. Il suffit d'enlever les fflush(stdin); et tout est bon.
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

  12. #72
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Au passage, je pense que cette entrée de la F.A.Q. est fausse, car la routine en question s'arrête soit au premier retour à la ligne et il peut y avoir des données après, soit sur un EOF qui n'arrivera jamais si l'entrée standard est une console.
    C'est surtout que son contexte d'utilisation n'est pas explicité.
    Un EOF peut intervenir sur une console (encore faut-il le faire exprès) ou plus généralement sur stdin qui peut avoir été redirigé (freopen()).
    La fonction peut également facilement être adaptée sur un flux d'entrée (texte) autre que stdin.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  13. #73
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    J'ai trouvé la réponse sur :http://www.developpez.net/forums/d54...e-retour-send/

    Je rajoute un paramètre lors de l'envoi du message à la fonction send :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    		rc = send(sd, buffer, strlen(buffer), MSG_NOSIGNAL);	/* envoie du message au serveur				*/
    							/* MSG_NOSIGNAL pour que l'envoie ne plante pas si le serveur est mort	*/
    Voici ce qui se passe chez le client :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ ./a.out 
    30 : numéro 0 a rejoint le canal.
     
    Message à envoyer au serveur (fin pour arrêter le serveur) : fin
    2 : 97
    Vérification OK
    Continuer ? (o/n) : o
     
    Message à envoyer au serveur (fin pour arrêter le serveur) : aze
    echec de send(): Broken pipe
    Est-ce bon selon vous ?
    Dans ce cas mon exemple est clos !
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

  14. #74
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par troumad Voir le message
    C'est peut-être un autre client qui l'a tué !
    Je fais quoi alors pour vérifier si le serveur est mort ? Le serveur envoie un message à tout ces clients pour dire qu'il est mort ?
    Si le serveur a réellement l'intention de partir (ou s'il a le temps de se voir mourir :-) ), oui, ce serait une délicate attention de prévenir tous les clients en leur envoyant un message. L'usage veut également que l'on éteigne explicitement le socket associé avec shutdown() avant de le refermer avec close().

    Autrement, tu peux mettre un handler de signal sur SIGPIPE. C'est probablement ce que font tous les clients IRC, mais cela nécessite d'apporter une attention particulière à la cause de ce SIGPIPE, qui peut être dû à n'importe quoi.

    Autrement, le mieux est de conserver le fonctionnement normal du système. Par exemple, les applications graphiques sous UNIX utilisant X-Window sont en fait des clients se connectant au serveur X. La chute dudit serveur provoque automatiquement l'envoi d'un signal vers toutes les applications qui y sont connectées, et donc leur re-fermeture automatique. Et cela, même si ni le serveur ni les applications clientes ne sont prévues pour gérer ce cas de figure (en fait, la X-lib reconnaît ce cas, bien sûr, mais se contente de faire le ménage).

    C'est aussi pour cela que ton client, comme le serveur auquel il se connecte, devrait gérer ses descripteurs avec poll() ou select(). L'idée est toujours de se mettre à l'écoute de n descripteurs — qui peuvent être des sockets ou des descripteurs ordinaires — et de se débloquer dès que l'un d'eux à quelque chose à dire. Ça peut être le socket quand le serveur envoie un message comme l'entrée standard quand c'est l'utilisateur qui saisit une commande.

    Je suis assez intéressé par ce point qui n'a rien à voir avec le sujet traité ici Certes, là, je récupère toute la chaîne entrée sans me poser des questions sur le formatage. Pour la récupération du o/n (fin du client), j'avais déjà une boucle pour vider le buffer jusqu'au signal "entrée".
    Le plus simple dans ce cas, c'est scanf(), alors.

    Mais la plupart du temps, il vaut mieux aller au plus simple et laisser le système adopter son comportement par défaut à moins d'avoir une raison vraiment justifiée de procéder ainsi. Par exemple, l'utilisateur de ton programme peut avoir pipé la sortie d'un script à ton programme pour le télécommander. Dans ce cas, le vidage clavier explicite risque d'être un handicap.

    En plus, si tu voulais être parfaitement irréprochable sur ce point, il faudrait que tu vérifies que ce que tu vides est bien le buffer d'un clavier. Autrement dit, que tu t'assures que ton processus est bien relié à une console.

    nb : je ne peux plus modifier mon code source car ça fait trop longtemps qu'il a été posté. Il suffit d'enlever les fflush(stdin); et tout est bon.
    Ok, mais si tu veux que ton code serve d'exemple, il faudra encore nettoyer quelques points.

    Citation Envoyé par diogene Voir le message
    C'est surtout que son contexte d'utilisation n'est pas explicité.
    Un EOF peut intervenir sur une console (encore faut-il le faire exprès) ou plus généralement sur stdin qui peut avoir été redirigé (freopen()).
    La fonction peut également facilement être adaptée sur un flux d'entrée (texte) autre que stdin.
    Certes, mais la F.A.Q. précise bien « comment vider le buffer clavier ? ». Cela m'ennuie un peu parce que même dans le cas où l'on sait que l'on est relié à une console, la routine n'est pas fiable. Si j'insère une temporisation de dix secondes pour laisser le temps à l'utilisateur de rentrer du texte, que j'appelle la fonction et que j'affiche ce qui suit, avec le code suivant :

    Code C : 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
    #include <stdio.h>
    #include <unistd.h>
     
    void clean_stdin(void);
     
    int main (void)
    {
        int c;
     
        sleep (10);
        clean_stdin();
     
        setbuf (stdout,NULL); /* Affichage immédiat sur la SORTIE standard */
        puts ("Lecture du tampon de l'entrée standard :");
        while ((c=fgetc(stdin))!=EOF) putchar (c);
     
        return 0;
    }

    … et que je saisis le code suivant dans l'intervalle :

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ ./programme
    Abcde<Return>
    Fghij<Return>
    Klmno<Ctrl-D>

    (on remarque l'absence de « Return » avant le Ctrl-D final), j'obtiens :

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Lecture du tampon de l'entrée standard :
    Fghij
    Klmno

    Donc le buffer n'est pas vide après l'appel à la fonction. À l'inverse, et c'est là le plus gênant à mon avis, si le buffer est réellement vide à l'appel de la fonction (cas le plus probable) ou s'il ne l'est pas, mais que j'ai terminé la saisie par Ctrl-D sans insérer de retour à la ligne, alors la fonction de nettoyage va rester bloquée en lecture jusqu'à ce que l'utilisateur se décide à entrer un retour à la ligne. En tout état de cause, EOF ne permet pas de savoir si le buffer d'entrée d'un processus relié à une console est vide…

    Voici ce que je propose à la place, sous systèmes compatibles POSIX :

    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
    #ifndef _POSIX_SOURCE
    #define _POSIX_SOURCE
    #endif
     
    #include <errno.h>
    #include <stdio.h>
    #include <fcntl.h>
     
    /* Vide le buffer d'entrée d'un flux utilisable
     * en lecture. Renvoie 1 en cas d'échec, 0 sinon. */
     
    int fclearbuf (FILE * f)
    {
        int ret = 1;
        int fd = -1;
     
        if (f!=NULL)
        if ((fd=fileno(f))>=0)
        {
            long flags  = 0;
     
            flags = (long)fcntl (fd,F_GETFL,0);
            if (!(flags & O_WRONLY))
            {
                char buffer [64];
     
                fcntl (fd,F_SETFL,flags | O_NONBLOCK);
                while (fread(buffer,sizeof buffer,1,f)==1);
                if (ferror(f) && errno == EWOULDBLOCK)
                {
                    clearerr (f);
                    ret = 0;
                }
                fcntl (fd,F_SETFL,flags);
            }
        }
     
        return ret;
    }

  15. #75
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    J'ai donc rajouté ceci lors de la fermeture du serveur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	  shutdown(sd,SHUT_RDWR);
    	  close(sd);
    	  remove(SERVER_PATH);
    As-tu vu ma remarque sur MSG_NOSIGNAL ? Selon moi, elle gère correctement la mort du serveur.

    Après, tu fais une remarque sur le scanf, c'est surtout son utilisation qui me fait utiliser les fflush(stdin). En effet, si tu fait un scanf("%d",&i) et que l'utilisatur rentre 12.456fdsf, seul le 12 sera lu et il restera .456fdsf dans le buffer ! Tu gères ce cas comment ? Sans parler des mélanges de scanf et getchar qui sont catastrophiques ! Peut-être avec ta fonction int fclearbuf (FILE * f) *
    Finalement, scanf est complètement déconseillé !

    Quels seraient les point à modifier pour faire de ce programme un exemple simple ? Ne pas perdre l'idée qu'un exemple soit simple... C'est à dire que si l'exemple ne porte pas sur la récupération des entrées claviers, unscanf peut-être acceptable si on met un avertissement sur l'utilisation su scanf en début d'exemple.

    * : dans ce cas, on sort du cas simple souhaité ici.
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

  16. #76
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    @Obsidian
    Ce que tu dis est exact et le titre de la FAQ est mal choisi : ce n'est effectivement pas une fonction qui vide le buffer d'entrée dans un cadre général.
    En fait, historiquement, cette fonction a été mise dans la FAQ simplement pour répondre aux problèmes fréquents posés par l'utilisation de scanf()consécutifs, du genre
    scanf("%d",...);
    scanf("%c",...);
    avec l'inconvénient évident qu'il faut que le buffer ne soit pas vide lors de l'appel à la fonction.

    Elle est simple et utile pour cet usage, mais il faudrait préciser le contexte d'utilisation de cette fonction (et adapter son titre).
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  17. #77
    Expert éminent sénior

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 603
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 603
    Points : 17 913
    Points
    17 913
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par troumad Voir le message
    Et c'est quoi cette histoire de poll ?
    Citation Envoyé par Obsidian Voir le message
    Non, effectivement, mais c'est normal : le signal émis ne concerne que le processus destinataire et n'a de sens que pour lui. Cela dit, la mort du processus concerné devrait provoquer la fermeture de ses sockets par le système et, de là, provoquer des SIGPIPE chez les processus qui y étaient toujours reliés.

    Ce qui est surprenant, c'est que cela ne soit pas immédiat, même avec un socket de type SOCK_STREAM. Cela dit, un sock_stream est littéralement un socket orienté flux. Cela n'implique pas forcément qu'il s'agisse d'une liaison orientée connexion.
    Citation Envoyé par troumad Voir le message
    C'est peut-être un autre client qui l'a tué !
    Je fais quoi alors pour vérifier si le serveur est mort ? Le serveur envoie un message à tout ces clients pour dire qu'il est mort ?


    J'ai juste remarqué (le système client/serveur sur lequel je travaillais était "critique", c'est à dire que opérationnellement il était vital (au vrai sens) de garantir que rien ne crashe jamais et que l'on relance automatiquement les serveurs/clients si l'un se plantait tout en gardant les requêtes en cours), que le moyen le plus "catch all" était d'avoir simultanément les signal handlers ET les polls.

    Les fonctions utilisées par poll sont les seules à vérifier l'état d'un socket SANS en modifier l'état...

    Une utilisation telle que :

    Code C : 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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
     
    /*
     * C h e c k s _ C o m m u n i c a t i o n
     *
     */
    static int Checks_Communication ( int Canal_In, int Canal_Out )
    {
       int             s, ncar_a_lire, ss ;
       struct pollfd   fds[2] ;
     
       fds[0].events = POLLOUT ;
       fds[1].events = POLLIN ;
     
    /*
    --- Assigns the values for the server to be checked
    */
       fds[0].fd = Canal_Out ;
       fds[1].fd = Canal_In ;
     
    /*
    --- Checks the state of the connection
    */
       s = poll (fds, 2, 200 );
     
    /*
    --- Either if failed (busy, frozen, error, or client hangup)
    */
       if ( (s <= 0) || 
    	(fds[0].revents & POLLERR) || (fds[1].revents & POLLERR) )
         {
           if ( s <= 0 )
    	 s = INFO ;
           else
    	 s = WARNING ;
         }
       else
           if ( (fds[1].revents & POLLHUP)|| (fds[0].revents & POLLHUP) ||
                (fds[1].revents & POLLNVAL)|| (fds[0].revents & POLLNVAL) )
    	   s = ERROR ;
           else 
    	 {
    	   /* Otherwise it is ok to try and write on it */
     
    	   ss = ioctl(fds[1].fd, FIONREAD, &ncar_a_lire);
    	   if ( (ncar_a_lire == 0) && (ss >= 0) && (s == 2) && (fds[1].revents & POLLIN) )
    	       s = ERROR ;
    	   else
    	       s = SUCCESS ;
    	 }
     
       return (s);
    }
     
     
     
    /*
     * S e c u r e _ W r i t e _ C o m m u n i c a t i o n
     *
     */
    static int Secure_Write_Communication ( int Canal_In, int Canal_Out, char *command, int Longu )
    {
      int    s, i ;
      time_t now ;
     
      if ( (i = Checks_Communication (Canal_In, Canal_Out)) == SUCCESS )
        {
              s = write ( Canal_Out, command, Longu) ;
               ....
        }
     
       return (s);
    }


    donnait, couplé avec un signal handler qui termine proprement en cas de SIGKILL, SIGTERM, SIGQUIT, SIGPIPE, SIGSTOP, un résultat parfait...
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  18. #78
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par troumad Voir le message
    J'ai donc rajouté ceci lors de la fermeture du serveur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	  shutdown(sd,SHUT_RDWR);
    	  close(sd);
    	  remove(SERVER_PATH);
    As-tu vu ma remarque sur MSG_NOSIGNAL ? Selon moi, elle gère correctement la mort du serveur.
    Oui, désolé. J'ai mis une heure à poster mon message et tu avais déposé le tien entre temps.

    Après, tu fais un remarque sur le scanf, c'est surtout son utilisation qui me fait utiliser les fflush(stdin). En effet, si tu fait un scanf("%d",&i) et que l'utilisatur rentre 12.456fdsf, seul le 12 sera lu et il restera .456fdsf dans le buffer ! Tu gères ce cas comment ? Sans parler des mélanges de scanf et getchar qui sont catastrophiques !
    Finalement, scanf est complètement déconseillé !
    Je parlais surtout du cas où tu voulais lire un caractère (« o » ou « n ») puis abandonner le reste de la ligne jusqu'au retour. Tu peux faire cela en une opération avec scanf() sans implémenter toi-même la boucle.

    Quels seraient les point à modifier pour faire de ce programme un exemple simple ? Ne pas perdre l'idée qu'un exemple soit simple... C'est à dire que si l'exemple ne porte pas sur la récupération des entrées claviers, unscanf peut-être acceptable si on met un avertissement sur l'utilisation su scanf en début d'exemple.
    Déjà, il faut revenir à l'objectif initial. Est-ce que tu cherches simplement à savoir si un programme est déjà ouvert ou est-ce que tu veux vraiment faire un « mini-IRC », c'est-à-dire deux applications dialoguant ensembles sur la durée ?

    Après, même si l'exemple est simple, il faut qu'il irréprochable sur tous les points (notamment la gestion des erreurs) car les gens qui suivront cet exemple ne le remettront pas en question. Et plus important encore, ils ne comprendront pas forcément en une seule fois tout ce qu'ils font. Il est donc important de leur donner d'emblée les bonnes habitudes.

  19. #79
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    Le but de cet exemple est l'utilisation, d'un socket AF_UNIX avec la possibilité pour le serveur de réceptionner plusieurs clients simultanément. Sans le select, on bloquait à la réception d'un client à la fois.
    Il y a en plus l'originalité (c'était le but premier de ma demande), de choisir l'état client ou serveur s'il y a ou non un serveur déjà ouvert.
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

  20. #80
    Rédacteur/Modérateur
    Avatar de troumad
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2003
    Messages
    5 597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 5 597
    Points : 7 832
    Points
    7 832
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Il est donc important de leur donner d'emblée les bonnes habitudes.
    Et pour moi aussi de tout comprendre
    Donc, là, je regarde la sortie du serveur que j'ai faite. Je n'ai fermé que le slot qui est à l'écoute d'une éventuelle nouvelle demande. Il faudrait sûrement que je rajoute la fermeture de tous les autres slots non ?

    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
    	  } while (on);
    	  if (shutdown(sd,SHUT_RDWR)<0)
    	  {
    	    perror("echec de shutdown() ");
    	  }
    	  if (close(sd)<0)
    	  {
    	    perror("echec de close() ");
    	  }
    	  for (i=0;i<NCNX;++i)				/* Parcourt les entrées possibles					*/
    	    if (slot[i]>=0)				/* Si l'entrée est encore active					*/
    	    {
    	      if (shutdown(slot[i],SHUT_RDWR)<0)	/* fermer l'entrée							*/
    	      {
    		perror("echec de shutdown() ");
    	      }
    	      if (close(slot[i])<0)			/* fermer le descripyeur de fichier					*/
    	      {
    		perror("echec de close() ");
    	      }
    	    }	
    	  remove(SERVER_PATH);
    À ce niveau je suis désagréablement surpris par la présence obligatoire de "remove(SERVER_PATH)" pour supprimer "srwxrwxr-x 1 troumad troumad 0 mai 14 14:44 /tmp/server=".

    nb : je mettrais mon programme avec l'affichage de la présence d'erreurs quand j'aurais fini de relever les petites questions du genre afin de pouvoir modifier le plus longtemps possible la version que je mettrais en ligne
    Modérateur Mageia/Mandriva Linux
    Amicalement VOOotre
    Troumad Alias Bernard SIAUD à découvrir sur http://troumad.org
    Mes tutoriels : xrandr, algorigramme et C, xml et gtk...

Discussions similaires

  1. Vérifier que le programme est ouvert
    Par Loenix dans le forum Programmation multimédia/Jeux
    Réponses: 2
    Dernier message: 14/05/2009, 15h50
  2. Vérifier si un programme est ouvert
    Par wonderboutin123 dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 03/02/2008, 11h36
  3. Vérifier si calc windows est ouverte ou pas???
    Par electrosat03 dans le forum Contribuez
    Réponses: 4
    Dernier message: 10/03/2006, 19h28
  4. Vérifier qu'un formulaire est ouvert
    Par com800 dans le forum WinDev
    Réponses: 2
    Dernier message: 07/04/2005, 20h27
  5. Vérifier si une form est ouverte
    Par nivet dans le forum Langage
    Réponses: 6
    Dernier message: 23/11/2004, 09h17

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