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 :

Utiliser ligne de commande Linux dans un programme C


Sujet :

C

  1. #21
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    C'est une bonne chose : ça veut dire que tu débutes mais que tu comprends vite et sais retrouver seul l'information qu'il te manque.
    J'avoue que je suis bien motivé aussi ^^ Plus je découvre Linux (et les systèmes Unix en général), plus je trouve ça génial.. même si des fois ça demande un réel effort de compréhension, je trouve que ça vaut vraiment le coup!

    Citation Envoyé par Obsidian Voir le message
    Tu as surtout dû remarquer que le premier des deux pairs reste en attente le temps que tu lances le second. Ce n'est pas anodin.
    Exactement, c'est ce que je voulais dire lorsque je disais "dans les deux sens"^^


    Citation Envoyé par Obsidian Voir le message

    Et ce n'est que le début ! Tout UNIX est comme ça. Enfin, au moins sous sa forme traditionnelle car les UNIX libres, bien qu'excellents en eux-mêmes, servent aujourd'hui de plateforme pour y faire fonctionner des environnements de bureau (GNOME, par exemple) qui, eux, laissent beaucoup moins de latitude à leur utilisateur.
    c'est vrai que plus ça va, moins je me sers de l'environnement graphique.. je n'aurai pas cru dire ça un jour, mais plus on s'en sert, plus je trouve la console excellente ! Petit à petit je découvre son efficacité et à quel point on peut aller encore plus vite que dans un environnement graphique.

    Citation Envoyé par Obsidian Voir le message

    Tu as peut-être lancé plusieurs fois le même processus ou laissé tourner plusieurs clients en lecture sur le même tube.
    j'ai bien fait attention à ça en faisant un ps aux | grep snmp et en faisant des kill si nécessaire... mais ça se peut j'en ai oublié..


    Citation Envoyé par Obsidian Voir le message
    En outre, je ne vois pas l'option « -f » dans ta ligne de commande, donc snmptrap passe en arrière plan. Tu récupères la main dans ton terminal mais lui continue d'accaparer le tube et tant qu'il ne l'a pas refermé, il n'y a pas de raison pour que cat se termine de lui-même.
    hum hum, je comprends.. ça se peut le problème vient bien de la..

    Citation Envoyé par Obsidian Voir le message
    Essaie ps auxw | grep snmptrap pour voir combien tu en as lancés.
    Bah à priori, même si j'ai fait en sorte qu'il n'y en ai pas plusieurs,il est possible que j'en ai laissé un.. ça doit bien être le snmptrap qui devait continuer en arrière plan..


    Citation Envoyé par Obsidian Voir le message
    Là, pour le coup, faire un popen() sur « cat » ne sert vraiment à rien ! Si tu veux récupérer le contenu du fichier en lecture, alors il faut ouvrir le fichier, tout simplement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        fichier = fopen("/var/log/snmp/snmptrapd.log","r");
    Ok, tout simplement..
    L'avantage d'utiliser le pipe plutôt que le fichier lui même se situe dans la rapidité? Je vais peut être essayer une fois que je l'aurai fait marché comme ça d'utiliser inotify pour voir si je peux le connecter à un SLOT dans Qt pour éviter d'avoir à ouvrir le pipe à intervalles régulier mais seulement lorsque cela est nécessaire..
    Stay a while and listen...

  2. #22
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Un fichier et un pipe ne se comportent pas tout à fait de la même manière. Par exemple :

    - Si tu lis un fichier vide ou au delà de la fin du fichier, le read retourne immédiatement sans lire de données. Si tu lis un pipe vide, le read bloque.

    - Tu ne peux pas te déplacer (seek) dans un pipe.

    - Un pipe a une "taille" limité. Si tu écris dans un pipe qui est plein, le write bloque jusqu'à ce de la place se libère (c'est-à-dire, que quelqu'un lise suffisamment de données).

  3. #23
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Alors j'ai compris pourquoi cat ne s'arrêtait pas.
    En fait il s'arrête lorsque je stop le daemon:
    sudo /etc/init.d/snmptrapd stop
    Par contre si je start le daemon et que j'envoie un TRAP dans un terminal, et que ensuite dans un autre terminal je lance cat snmptrapd.log , il ne se passe rien, cat n'affiche rien..


    Ensuite j'ai juste re-testé ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
       FILE *fichier = NULL;
      char chaine[100];
     
      fichier = fopen("/var/log/snmp/snmptrapd.log","r");
     
      if(fichier != NULL)
      {
          fgets(chaine, 100,fichier);
          affichage->append(QString(chaine));// printf("%s",chaine);
          fclose(fichier);
      }
    Et mon programme se comporte de la même façon. Si je lit le pipe et que j'envoie les trap après, je les récupère bien et ils s'affichent. Par contre si je fais le contraire, c'est à dire démarrer le daemon et envoyer des traps, etpuis ensuite lire le pipe, là il n'affiche rien .. comme si le daemon ne savait pas écrire dans un pipe qui ne soit pas déjà ouvert par ailleurs.
    Stay a while and listen...

  4. #24
    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 622
    Points
    23 622
    Par défaut
    Citation Envoyé par zodd Voir le message
    Alors j'ai compris pourquoi cat ne s'arrêtait pas.
    En fait il s'arrête lorsque je stop le daemon:
    sudo /etc/init.d/snmptrapd stop
    C'est dû au fait que ton dæmon conserve le fichier ouvert parce qu'il pense en être le seul exploitant, et parce qu'il a besoin d'y déposer rapidement les informations quand elles arrivent.

    Le fait de mettre fin au processus referme immédiatement tous les descripteurs de fichiers en sa possession et, donc, referme le tube. « cat » reçoit alors une « fin de fichier » officielle et donc, se termine à son tour de son propre gré. Mais « cat » ne saura jamais s'il a vraiment atteint la fin d'un fichier ordinaire ou si c'est un tube qui a été refermé à l'autre extrémité.

    Ensuite j'ai juste re-testé ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
       FILE *fichier = NULL;
      char chaine[100];
     
      fichier = fopen("/var/log/snmp/snmptrapd.log","r");
     
      if(fichier != NULL)
      {
          fgets(chaine, 100,fichier);
          affichage->append(QString(chaine));// printf("%s",chaine);
          fclose(fichier);
      }
    Attention : cet extrait est incorrect !

    Tel qu'il est écrit, ton programme vérifie si le fichier a bien été ouvert puis, si c'est le cas, lis une seule ligne, l'affiche, referme le fichier et sort du bloc.

  5. #25
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    En fait j'ai écrit ce bout de code pour vérifier globalement que ça fonctionne. Effectivement si j'en lève le fclose, effectivement je peux lancer mon bout de programme après qu'un trap ai été envoyé et la première ligne de ce qui a été écrit s'affiche bien...

    Le problème c'est qu'au départ j'avais écrit ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    FILE *fichier = NULL;
      char chaine[100];
     
      fichier = fopen("/var/log/snmp/snmptrapd.log","r");
     
      if(fichier != NULL)
      {
          while(fgets(chaine, 100,fichier) != NULL)
          {
          affichage->append(QString(chaine));
          }
      }
    Mais là le programme reste bloqué au while et n'affiche rien. De plus je suppose que tout comme cat, il ne sais pas qu'on est arrivé à la fin du "fichier" et donc du coup il attend encore..? mais j'aurai pensé qu'il afficherai au moins ce qui rentre dans le pipe...

    De plus je ne sais pas comment détecter comment vérifier que le pipe a des données en attente de lecture.. c'est la que inotify entre en jeu je suppose..?

    Edit: Alors pour l'instant j'ai mis le code ci-dessous dans un timer (j'ai mis deux lignes (de façon moche) lues car 2 lignes sont écrites par trap reçut):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     FILE *fichier = NULL;
      char chaine[100];
     
      fichier = fopen("/var/log/snmp/snmptrapd.log","r");
     
      if(fichier != NULL)
      {
     
          fgets(chaine, 100,fichier);
          affichage->append(QString(chaine));
          fgets(chaine, 100,fichier);
          affichage->append(QString(chaine));
      }
    Le problème c'est que le programme reste totalement coincé sur le fgets tant que je ne reçoit pas quelque chose dans le pipe. Ce qui est normal en fait car dans ce cas il n'y a pas de notion de fin de fichier et fgets attends des données.. en fait il faudrait que je puisse soit être averti qu'il y a des données dans le pipe, ou alors si j'utilise un timer comme dans mon exemple, de ne pas rester coincé si aucune donnée n'est présente dans le pipe.

    Mais ça explique pourquoi le première exemple reste coincé et rien ne s'affiche. Il s'agit du même problème.
    Stay a while and listen...

  6. #26
    Membre éclairé
    Inscrit en
    Juillet 2012
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 231
    Points : 870
    Points
    870
    Par défaut
    Citation Envoyé par zodd Voir le message
    De plus je ne sais pas comment détecter comment vérifier que le pipe a des données en attente de lecture.. c'est la que inotify entre en jeu je suppose..?
    Vu que tu es avec un pipe, je pense qu’un select serait plus sympa à utiliser du coup.

  7. #27
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    effectivement, je vais essayer de tester ça^^

    j'ai une autre question (une de plus ) . Actuellement le pipe que j'utilise a été créé par moi même dans le terminal. j'ai comprit comment créer un pipe de base avec la fonction pipe(). Mais dans mon application, c'est un pipe qui remplace un fichier déjà existant.. Donc comment on pourrait le créer en le forçant à être exactement le pipe nommé /var/log/snmp/snmptrapd.log ?

    Par exemple mon programme renommerai le fichier original, créerai le pipe le remplaçant et ensuite le refermerai et redonnerai son nom au fichier original.


    Edit: alors je viens de réaliser quelquechose qui ne marche pas mais au moins mon programme n'est plus bloqué.. j'appelle toujours ma fonction depuis un timer toutes les 500ms.. et voilà ce qu'il y a dans ma fonction:
    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
     
    struct timeval tv;
      fd_set readfs;
      int retval;
     
      FILE *fichier = NULL;
      char chaine[100];
     
      fichier = fopen("/var/log/snmp/snmptrapd.log","r");
     
      if(fichier != NULL)
      {
          FD_ZERO(&readfs);
          FD_SET(fileno(fichier), &readfs);
          tv.tv_sec = 0;
          tv.tv_usec = 500;
          retval = select(1, &readfs, NULL, NULL, &tv);
     
          if (retval == -1)
               perror("select()");
           else if (retval)
           {
              fgets(chaine, 100,fichier);
              affichage->append(QString(chaine));
              fgets(chaine, 100,fichier);
              affichage->append(QString(chaine));
           }
           else
               affichage->append("No data in the pipe.\n");
    En gros avec fileno je récupère le descripteur de fichier. je fait un select pour savoir si il y a quelque chose à lire dans le pipe.. bon je creuse, je creuse..lol
    Stay a while and listen...

  8. #28
    Membre éclairé
    Inscrit en
    Juillet 2012
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 231
    Points : 870
    Points
    870
    Par défaut
    Citation Envoyé par zodd Voir le message
    j'ai une autre question (une de plus ) . Actuellement le pipe que j'utilise a été créé par moi même dans le terminal. j'ai comprit comment créer un pipe de base avec la fonction pipe(). Mais dans mon application, c'est un pipe qui remplace un fichier déjà existant.. Donc comment on pourrait le créer en le forçant à être exactement le pipe nommé /var/log/snmp/snmptrapd.log ?
    Pour créer un pipe avec un nom dans le terminal tu utilises mkfifo.
    Et bien en C POSIX, il y a aussi mkfifo.

  9. #29
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    ok tout bêtement... c'est magique

    (bon par contre je me galère bien avec sélect.. il me retourne toujours 0.
    Stay a while and listen...

  10. #30
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Bon alors, j'ai "automatisé" la création de mon pipe nommé :
    ajout de ça:
    #include <sys/stat.h>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        rename("/var/log/snmp/snmptrapd.log","/var/log/snmp/oldsnmptrapd.log");
        mkfifo("/var/log/snmp/snmptrapd.log",S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    et au moment de quitter le programme je fais ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        remove("/var/log/snmp/snmptrapd.log");
        rename("/var/log/snmp/oldsnmptrapd.log","/var/log/snmp/snmptrapd.log");
    ça marche nikel !

    Bon il ne me reste plus qu'à trouver une solution pour ne pas rester bloqué sur fgets si il n'y a pas de datas dans le pipe et idéalement en plus, n'aller le consulter que si il y a des datas dedans.

    j'ai testé ça mais sans succès:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int fd;
         char chaine[20];
     
         fd=open("/var/log/snmp/snmptrapd.log",O_RDONLY | O_NDELAY| O_NONBLOCK);
     
             read(fd, chaine, 20);
             affichage->append(QString(chaine));
    Stay a while and listen...

  11. #31
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Tu peux tester la présence de données avec select() ou poll().

    Une autre solution pourrait être d'ouvrir ton FIFO avec le flag O_ASYNC. Dans ce cas, tu reçois un signal (SIGIO) quand des données deviennent disponibles.

    Par contre je ne comprends pas trop comment ton truc peux marcher. Tu remplaces le fichier de log par un FIFO, mais le problème c'est que si tu ne redémarres pas ton démon (ou en tout cas si tu ne forces pas le démon à réouvrir son fichier de log), il écrira toujours dans le fichier, pas dans le FIFO. Du côté du démon le fd est toujours associé au même inode, qui est toujours associé à l'ancien fichier sur le disque même si son nom a changé.

  12. #32
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Et pourtant ça marche bien. Les données envoyées par le daemon sont bien envoyées dans le pipe nommé qui remplace le fichier. je l'affiche bien avec cat dans le terminal.

    J'ai essayé d'utiliser select() comme tu peux le voir dans mon exemple précenet mais mon code me renvoie toujours qu'il n'y a pas de data dans le pipe.. je vais tester avec poll().


    L'utilisation du flag O_ASYNC est une bonne idée, c'est visiblement bien ce que je cherche à faire.. il me reste à comprendre comment récupérer le signal SIGIO (et apprendre ce que c'est).
    Stay a while and listen...

  13. #33
    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 622
    Points
    23 622
    Par défaut
    Citation Envoyé par matafan Voir le message
    Par contre je ne comprends pas trop comment ton truc peux marcher. Tu remplaces le fichier de log par un FIFO, mais le problème c'est que si tu ne redémarres pas ton démon (ou en tout cas si tu ne forces pas le démon à réouvrir son fichier de log), il écrira toujours dans le fichier, pas dans le FIFO. Du côté du démon le fd est toujours associé au même inode, qui est toujours associé à l'ancien fichier sur le disque même si son nom a changé.
    Soit il lance lui-même le dæmon comme on lui a expliqué un peu plus haut dans le fil, soit le dæmon a le bon goût de libérer le descripteur de fichier quand il ne s'en sert pas pendant une période donnée…

  14. #34
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Je lance le daemon après la création du pipe ^^ Alors 0_ASYNC fait en sorte que le programme ne reste pas bloqué^^ par contre j'ai encore un truc bizarre.. je fouille et je reviens une fois que j'ai compris ce qui se passe.. (si j'y arrive.lol)

    Edit: bon après avoir regardé ce qu'il se passe de plus près, mkfifo("/var/log/snmp/snmptrapd.log",S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_ASYNC); ne créé pas le pipe, en fait c'est daemon, en venant écrire dans le fichié qui le créaient et et donc mon fgets ne faisait que lire le fichier "normal"..
    Stay a while and listen...

  15. #35
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Bon j'ai exploré avec poll(): et le problème persiste dans la mesure où mon programme rester coincé au moment où je fais le fopen et ne se décoince que quand une donnée rentre dans le pipe...

    j'appelle cette fonction toutes les 500ms, et je "poll" durant 100 ms à attendre si il y a des DATA prêtes à être lu.

    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
     
    int fd;
    struct pollfd fdinfo[1];
    int ret;
    int timeout_msecs = 100;
    FILE *fichier = NULL;
     char chaine[100];
     
              fichier = fopen("/var/log/snmp/snmptrapd.log","r");
     
              fdinfo[0].fd = fileno(fichier);
              fdinfo[0].events = POLLIN|POLLPRI ;
     
              ret = poll(fdinfo, 1, timeout_msecs);
              if(ret>0)
              {
                  if((fdinfo[0].revents & POLLIN)||(fdinfo[0].revents & POLLPRI))
                   {
                        fgets(chaine, 100,fichier);
                        affichage->append(QString(chaine));
                        fgets(chaine, 100,fichier);
                        affichage->append(QString(chaine));
                   }
                   else
                   {
                      affichage->append("Bad Event.\n");
                   }
     
              }
              else
                  affichage->append("No data in the pipe.\n");

    Bon je tiens quelque chose qui commence à fonctionner sans bloquer le reste de mon programme:
    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
    int fd;
    struct pollfd fdinfo[1];
    int ret;
    int timeout_msecs = 100;
     
     char chaine[60];
     
     
     
              fd=open("/var/log/snmp/snmptrapd.log",O_RDONLY | O_NDELAY| O_NONBLOCK);
              fdinfo[0].fd = fd;
              fdinfo[0].events = POLLIN|POLLPRI ;
              ret = poll(fdinfo, 1, timeout_msecs);
              if(ret>0)
               {
                  if((fdinfo[0].revents & POLLIN)||(fdinfo[0].revents & POLLPRI))
                   {
                     read(fd, chaine, 60);
                     affichage->append(QString(chaine));
                   }
              }
    Le problème c'est que read() est moins pratique que fgets() pour lire et donc en fonction du nombre de caractères, il me renvoie deux fois la fin de la dernière ligne, ou alors il affiche du garbage, etc.. j'approche du but !
    Stay a while and listen...

  16. #36
    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 622
    Points
    23 622
    Par défaut
    Citation Envoyé par zodd Voir le message
    Bon j'ai exploré avec poll(): et le problème persiste dans la mesure où mon programme rester coincé au moment où je fais le fopen et ne se décoince que quand une donnée rentre dans le pipe...
    C'est le principe du pipe, en effet, et d'une manière générale de tous les flux entrants, par défaut. Select() et poll() sont là pour te permettre de surveiller plusieurs descripteurs bloquants à la fois et de se débloquer dès qu'au moins l'un d'eux se débloque lui-même. Si tu ne surveille qu'un seul descripteur, select() et poll() sont inutiles, sauf à vouloir exploiter le timeout.

    N'oublie pas non plus qu'encore une fois, tu as écrit « if () {} » dans ton programme et pas « while () {} ». Ça veut dire qu'en l'occurrence, et en l'absence du reste du programme, dès que la première ligne sera lue, ton programme prendra fin.

    Tu peux utiliser O_NONBLOCK lorsque tu ouvres un fichier (ou assimilé) pour demander à recevoir l'erreur EAGAIN plutôt que rester en attente. C'est très utilisé mais, dans ton cas, il est nécessaire de vérifier si c'est bien la solution appropriée. Autrement tu risques de rentrer en attente active avec un processus consommant 100% du temps CPU pendant qu'il attend.

  17. #37
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Hé hé , et oui j'ai bien vu que le principe du pipe se retourne contre moi..

    Et je ne pense pas que tu as vu mon EDIT qui a du se croiser avec ton message.. Je me suis effectivement débrouillé avec O_NONBLOCK et là ça marche, j'ai bien le résultat espéré ^^ Je ne me suis pas servit des EAGAIN par contre.... il faut que je regarde ce que c'est^^


    Edit: Tu veux dire qu'à la place de POLL, je pourrai aussi faire ça? (je ne suis pas sur mon pc pour pouvoir tester..):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int fd;
    char chaine[60];
     
     
              fd=open("/var/log/snmp/snmptrapd.log",O_RDONLY | O_NDELAY| O_NONBLOCK);
              while(EAGAIN!=read(fd, chaine, 60))
                     affichage->append(QString(chaine));
    Pour le if à la place du while, j'ai fait exprès pour être sur de ne pas resté bloqué pour une "mauvaise" raison.

    Le truc c'est que j'ai une GUI et il ne faut pas qu'elle soit bloquée car l'utilisateur doit pouvoir faire d'autres choses en même temps... d'où le fait que j'utilise un timer pour faire un poll de temps en temps..
    L'idéal serait malgré tout de pouvoir me passer d'un timer et de poll et de travailler sur événement..
    Stay a while and listen...

  18. #38
    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 622
    Points
    23 622
    Par défaut
    Citation Envoyé par zodd Voir le message
    Je ne me suis pas servit des EAGAIN par contre.... il faut que je regarde ce que c'est^^
    « EAGAIN » signifie « Try Again Later » et est le code d'erreur que tu reçois lorsque l'appel n'a rien à te renvoyer et qu'il aurait bloqué en temps normal et en l'absence du flag.

    Edit: Tu veux dire qu'à la place de POLL, je pourrai aussi faire ça? (je ne suis pas sur mon pc pour pouvoir tester..):
    Pas à la place. Enfin pas tout-à-fait. De cette façon, tu te retrouves à écrire des chaînes tant qu'elle sont disponibles puis à passer à la suite. Fort bien, mais :
    • Il faut prévoir une autre boucle while autour de tout cela pour pouvoir y revenir et afficher la suite quand elle pointe le bout de son nez ;
    • Il faut voir ce qui se passe après. Si tu te retrouves dans une autre situation qui te rend simplement la main s'il n'y a aucun traitement à faire, alors ton programme va tourner en rond au lieu de laisser la main au système et consommer tout le temps disponible.


    Le truc c'est que j'ai une GUI et il ne faut pas qu'elle soit bloquée car l'utilisateur doit pouvoir faire d'autres choses en même temps... d'où le fait que j'utilise un timer pour faire un poll de temps en temps.. L'idéal serait malgré tout de pouvoir me passer d'un timer et de poll et de travailler sur événement..
    Le plus simple dans un premier temps serait de créer un thread tout simplement : tu laisse ton premier processus ne s'occuper que de la GUI (et éventuellement entrer dans la boucle principale de Qt) et de l'autre, tu crées un second processus qui tourne en arrière plan et qui s'occupe de faire le boulot de manière asynchrone, en effectuant les tâches à accomplir les unes après les autres et en se restant à l'écoute du tube quand il n'a rien à faire.

    Même si ça paraît élégant de prime abord, on essaie de n'y recourir à cette technique que si cela apporte un réel gain (par exemple, en cas parallélisme sur du multi-core) ou lorsque l'API a des lacunes que l'on ne peut contourner. Autrement, on essaie de trouver des solutions algorithmiques comme tu le fais pour faire tenir le tout dans un seul fil.

  19. #39
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    « EAGAIN » signifie « Try Again Later » et est le code d'erreur que tu reçois lorsque l'appel n'a rien à te renvoyer et qu'il aurait bloqué en temps normal et en l'absence du flag.
    C'est bien pratique ça et plus adapté que poll si on n'a qu'un seul tube à surveiller^^ c'est ça?

    Citation Envoyé par Obsidian Voir le message
    Pas à la place. Enfin pas tout-à-fait. De cette façon, tu te retrouves à écrire des chaînes tant qu'elle sont disponibles puis à passer à la suite. Fort bien, mais :
    • Il faut prévoir une autre boucle while autour de tout cela pour pouvoir y revenir et afficher la suite quand elle pointe le bout de son nez ;
    • Il faut voir ce qui se passe après. Si tu te retrouves dans une autre situation qui te rend simplement la main s'il n'y a aucun traitement à faire, alors ton programme va tourner en rond au lieu de laisser la main au système et consommer tout le temps disponible.
    Oui je comprends. Mais dans mon programme ma fonction est appelée périodiquement par un timer.. du coup je ne suis plus obligé de prévoir une autre boucle while. Ou alors je n'ai pas bien comprit ce que tu veux dire?
    A la limite je peux faire le fd=open("/var/log/snmp/snmptrapd.log",O_RDONLY | O_NDELAY| O_NONBLOCK); dans mon constructeur au lancement du programme et n'appeler que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    while(EAGAIN!=read(fd, chaine, 60))
                     affichage->append(QString(chaine));
    dans la fonction lancée par le timer?

    Je ne comprends pas bien ce que tu veux dire au deuxième point? mais utilisant un timer, je suppose que du coup entre chaque "interruption" timer, le système reprend bien la main.

    Citation Envoyé par Obsidian Voir le message
    Le plus simple dans un premier temps serait de créer un thread tout simplement : tu laisse ton premier processus ne s'occuper que de la GUI (et éventuellement entrer dans la boucle principale de Qt) et de l'autre, tu crées un second processus qui tourne en arrière plan et qui s'occupe de faire le boulot de manière asynchrone, en effectuant les tâches à accomplir les unes après les autres et en se restant à l'écoute du tube quand il n'a rien à faire.

    Même si ça paraît élégant de prime abord, on essaie de n'y recourir à cette technique que si cela apporte un réel gain (par exemple, en cas parallélisme sur du multi-core) ou lorsque l'API a des lacunes que l'on ne peut contourner. Autrement, on essaie de trouver des solutions algorithmiques comme tu le fais pour faire tenir le tout dans un seul fil.
    Je n'ai jamais utilisé la notion de thread, ce qui visiblement n'est pas une mauvaise chose^^

    Je me demande aussi, le daemon que j'utilise existe aussi sous forme de service pour Windows.. du coup mon programme devrait rester compatible..? Faudrait il que j'utilise un compilateur particulier tel que MinGW ou CygWIN par exemple?
    Stay a while and listen...

  20. #40
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Salut,
    alors j'ai testé ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
     fd=open("/var/log/snmp/snmptrapd.log",O_RDONLY | O_NDELAY| O_NONBLOCK);
    while(EAGAIN!=read(fd, chaine, 300))
                     affichage->append(QString(chaine));
    et en fait read me renvoie toujours quelque chose différent de EAGAIN même si il n'y a rien dans le pipe, du coup je reste coincé dans la boucle même si il n'y a pas de data dans le pipe..

    Par contre si je fais ça, ça fonctionne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     fd=open("/var/log/snmp/snmptrapd.log",O_RDONLY | O_NDELAY| O_NONBLOCK);
     do{
         ret=read(fd, chaine, 300);
         if(ret>0)
         affichage->append(QString(chaine));
     }
     while(ret>0);
    Je suis obligé de faire ça car sinon , si je fait un bête while(read(fd, chaine, 300)>0) ça marche un peu au début puis ensuite à chaque passage dans la fonction, même si il n'y a rien dans le pipe , le programme rentre quand même dans le while et exécute la ligne affichage->append(QString(chaine));.. ce qui fait que j'ai des sauts de ligne vide qui s'affichent.. alors qu'avec le do{}while{...}, je n'ai pas de ce problème..


    EDIT: Par contre, mon programme tel qu'il est là plante au bout d'un certain temps avec un buffer overflow.... :
    QProcessPrivate::createPipe: Cannot create pipe 0xd48320: Too many open filesJe suppose que ça vient du fait que j'appelle régulièrement open() et qu'il faut en fait que je le mette dans le constructeur..
    EDIT2: je confirme c'est bien ça il faut fd=open("/var/log/snmp/snmptrapd.log",O_RDONLY | O_NDELAY| O_NONBLOCK); dans le constructeur.
    Stay a while and listen...

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 3 PremièrePremière 123 DernièreDernière

Discussions similaires

  1. Réponses: 12
    Dernier message: 03/12/2010, 16h08
  2. Utiliser des commandes linux dans un shell
    Par Info_76 dans le forum Shell et commandes GNU
    Réponses: 4
    Dernier message: 20/03/2008, 12h03
  3. [Système] Commande Linux dans Programme PHP
    Par makohsarah dans le forum Langage
    Réponses: 3
    Dernier message: 10/09/2007, 12h36
  4. utilisation des commandes shell dans un programme C
    Par rasgueados dans le forum Linux
    Réponses: 15
    Dernier message: 03/08/2006, 17h25
  5. Réponses: 2
    Dernier message: 24/06/2003, 20h31

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