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 :

Signaux en C


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    152
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 152
    Par défaut Signaux en C
    Bonjour,

    Je commence à étudier l'utilisation des signaux en C, et j'ai du mal à programmer un récepteur/émetteur.
    Récepteur qui doit juste afficher le signal reçu (dès qu'il en reçois un). Et l’émetteur qui prend le pid du processus cible et lui envoi des signaux aleatoire en boucle.

    Je n'arrive donc pas à coder ça, je pense quand même comprendre comment ça marche et je sais aussi comment envoyer un signal avec kill, le différent type de signaux. Je me renseigne encore sur le signal handler, mais c'est assez confu pour moi.

    Si vous pouviez me donner des indications, je serai ravis !

    Merci d'avance.

  2. #2
    Membre émérite
    Avatar de Kirilenko
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    234
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 234
    Par défaut
    Bonjour,

    Le mieux est de prendre d'emblée de bonnes habitudes ; éviter signal et y préférer sigaction pour définir des handlers personnalisés, mieux documenté, mieux standardisé, bref, mieux. Pour attraper un certain nombre de signaux, tu peux utiliser un tableau. Exemple avec quatre signaux :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <signal.h>
    #include <stddef.h>
     
    int sigarray[] =
    {
        SIGINT,
        SIGABRT,
        SIGBUS,
        SIGUSR2
    };
    size_t sigsize = sizeof sigarray / sizeof *sigarray;
    On notera qu'on peut les partager entre les fichiers sources de l'émetteur et le récepteur afin de faciliter l'évolution du code. On peut donc très bien les mettre dans un module à part. Un fichier d'en-tête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #ifndef H_LP_SIGARRAY_20130420121903
    #define H_LP_SIGARRAY_20130420121903
     
    #include <stddef.h>
     
    extern int sigarray[];
    extern size_t sigsize;
     
    #endif
    Et un fichier source :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "sigarray.h"
    #include <signal.h>
    #include <stddef.h>
     
    int sigarray[] =
    {
        SIGINT,
        SIGABRT,
        SIGBUS,
        SIGUSR2
    };
     
    size_t sigsize = sizeof sigarray / sizeof *sigarray;
    Il faudra compiler le fichier source en même temps que celui de l'émetteur et du récepteur ; et inclure le fichier d'en-tête dans chacune des unités de traduction susmentionnées.

    La suite de l'algorithme consiste à affecter à chaque élément du tableau le même handler :

    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
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
     
    struct sigaction handler;
    size_t i;
     
    if (sigfillset(&handler.sa_mask) == -1)
    {
        perror("sigfillset");
        return EXIT_FAILURE;
    }
     
    handler.sa_handler = handle_signals;
    handler.sa_flags = 0;
     
    for (i = 0; i < sigsize; i++)
    {
        if (sigaction(sigarray[i], &handler, NULL) == -1)
        {
            perror("sigaction");
            return EXIT_FAILURE;
        }
    }
    Enfin, tu peux te mettre en attente d'un signal grâce à la fonction pause :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <sys/types.h>
    #include <unistd.h>
     
    printf("#%d is waiting for signals\n", (int)getpid());
     
    for (;;)
    {
        (void)pause();
    }
    Quant à la routine de traitement du signal, il suffit d'y afficher la valeur du paramètre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
     
    static void handle_signals(int signum)
    {
        (void)printf("#%d: Signal %d received\n", (int)getpid(), signum);
    }
    Du côté de l'émetteur, tu dois avoir toutes les clés en main pour le faire. Tu peux utiliser les arguments du main pour savoir le PID du processus à considérer comme cible.

    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
    #include <errno.h>
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
     
    long int pid;
     
    if (argc < 2)
    {
        fprintf(stderr, "Not enough command-line arguments\n");
        return EXIT_FAILURE;
    }
     
    errno = 0;
    pid = strtol(argv[1], NULL, 10);
     
    if ((pid == LONG_MIN || pid == LONG_MAX) && errno != 0)
    {
        perror("strtol");
        return EXIT_FAILURE;
    }
    Ensuite, on génère une valeur pseudo-aléatoire (contenant un léger biais, d'ailleurs), à chaque tour de boucle.

    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
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
     
    srand(time(NULL));
     
    for (;;)
    {
        int signum = rand() % sigsize;
     
        printf("#%d: Send next signal? ", (int)getpid());
        getchar();
     
        if (kill((pid_t)pid, sigarray[signum]) == -1)
        {
            perror("kill");
            return EXIT_FAILURE;
        }
    }
    L'ennui, c'est que, pour quitter les deux applications, il faut y aller à coup de signaux, justement. Mais tu peux aisément ajouter une interface par le biais d'entrées/sorties afin de rendre tout cela interactif.

    Voilà ce que j'obtiens à la fin (mea culpa si il y a des erreurs, de toute manière ce n'est pas fait pour être copié/collé comme tel) :

    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
    /* receiver.c */
     
    #include "sigarray.h"
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
     
    static void handle_signals(int signum)
    {
        printf("#%d: Signal %d received\n", (int)getpid(), signum);
    }
     
    int main(void)
    {
        size_t i;
     
        struct sigaction handler;
     
        if (sigfillset(&handler.sa_mask) == -1)
        {
            perror("sigfillset");
            return EXIT_FAILURE;
        }
     
        handler.sa_handler = handle_signals;
        handler.sa_flags = 0;
     
        for (i = 0; i < sigsize; i++)
        {
            if (sigaction(sigarray[i], &handler, NULL) == -1)
            {
                perror("sigaction");
                return EXIT_FAILURE;
            }
        }
     
        printf("#%d is waiting for signals\n", (int)getpid());
     
        for (;;)
        {
            (void)pause();
        }
     
        return EXIT_SUCCESS;
    }
    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
    51
    /* transmitter.c */
     
    #include "sigarray.h"
    #include <errno.h>
    #include <limits.h>
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <time.h>
     
    int main(int argc, char *argv[])
    {
        long int pid;
     
        if (argc < 2)
        {
            fprintf(stderr, "Not enough command-line arguments\n");
            return EXIT_FAILURE;
        }
     
        errno = 0;
        pid = strtol(argv[1], NULL, 10);
     
        if ((pid == LONG_MIN || pid == LONG_MAX) && errno != 0)
        {
            perror("strtol");
            return EXIT_FAILURE;
        }
     
        srand(time(NULL));
     
        for (;;)
        {
            int signum = sigarray[rand() % sigsize];
     
            printf("#%d: Send next signal? ", (int)getpid());
            getchar();
     
            if (kill((pid_t)pid, signum) == -1)
            {
                perror("kill");
                return EXIT_FAILURE;
            }
     
            printf("#%d Signal %d sent\n", (int)getpid(), signum);
        }
     
        return EXIT_SUCCESS;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /* sigarray.c */
     
    #include "sigarray.h"
    #include <signal.h>
    #include <stddef.h>
     
    int sigarray[] =
    {
        /* TODO */
    };
     
    size_t sigsize = sizeof sigarray / sizeof *sigarray;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /* sigarray.h */
     
    #ifndef H_LP_SIGARRAY_20130420121903
    #define H_LP_SIGARRAY_20130420121903
     
    #include <stddef.h>
     
    extern int sigarray[];
    extern size_t sigsize;
     
    #endif
    Bonne journée !
    Récursivité en C : épidémie ou hérésie ?

    "Pour être un saint dans l'Église de l'Emacs, il faut vivre une vie pure. Il faut se passer de tout logiciel propriétaire. Heureusement, être célibataire n'est pas obligé. C'est donc bien mieux que les autres églises" - Richard Stallman

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    152
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 152
    Par défaut
    Whao merci ! Je vais prendre le temps de bien comprendre tout ça !

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    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 442
    Par défaut
    Citation Envoyé par Raikyn Voir le message
    Whao merci ! Je vais prendre le temps de bien comprendre tout ça !
    Un gros +1 à Kirilenko pour avoir pris le temps de rédiger tout cela !

    Détail important : les signaux UNIX ne servent surtout pas à faire de la transmission de données entre deux processus ! C'est important parce que j'ai vu plusieurs profs faire la confusion (dont un des miens) et qu'on a même vu ici un étudiant tenter de transmettre des infos « en morse » d'un processus à l'autre en les émettant bit à bit et en utilisant SIGUSR1 pour un « zéro » et SIGUSR2 pour un « un ». Il avait fait cela avec beaucoup de sérieux mais se demandait pourquoi c'était si lent.

  5. #5
    Membre Expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Par défaut
    C'est un projet dans une certaine école le chat avec les deux signaux...
    Ca sert justement à montrer tout ce qu'il est possible de faire avec les interfaces systèmes, même si elles ne sont pas exactement faites pour cela ! xD
    ...et surtout apprendre à émettre et receptioner des signaux !
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    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 442
    Par défaut
    Citation Envoyé par Metalman Voir le message
    C'est un projet dans une certaine école le chat avec les deux signaux... Ca sert justement à montrer tout ce qu'il est possible de faire avec les interfaces systèmes, même si elles ne sont pas exactement faites pour cela ! xD
    C'était effectivement un projet scolaire mais je ne m'étais pas rendu compte que c'était le thème même de l'exercice :-\ Je suppose (au vu du smiley) que ton commentaire était ironique mais là, ce serait plutôt « montrer tout ce qu'il ne faut pas faire ». Dans une école, à moins que ce soit justement expliqué comme tel, c'est plutôt une mauvaise chose.

Discussions similaires

  1. Signaux CTS et RTS sur dialogue port COM
    Par chourmo dans le forum Composants VCL
    Réponses: 8
    Dernier message: 22/06/2005, 11h45
  2. [signaux] contrôler une apply python
    Par jean-jacques varvenne dans le forum Général Python
    Réponses: 1
    Dernier message: 22/03/2005, 15h06
  3. [Amstrad] Signaux à gérer port E/S pour lire ROM
    Par Masterglob dans le forum Autres architectures
    Réponses: 7
    Dernier message: 12/01/2005, 12h03
  4. [INFO]Signaux Linux et Java
    Par el3gans dans le forum Général Java
    Réponses: 5
    Dernier message: 26/11/2004, 00h17
  5. [C#] Gérer les signaux genre ctrl+c?
    Par BleudeBromothymol dans le forum Windows Forms
    Réponses: 8
    Dernier message: 17/11/2004, 15h32

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