Le carnet On est
Cours 6 · encre charbon

Les files de messages

Boîtes aux lettres entre processus : des paquets typés, sélectionnables, FIFO. IPC Système V et le pendant POSIX temps réel.

~ 25 min de lecture IPC System V & POSIX MQ 14 flashcards · 7 quiz

📄 Ressources du cours

📥 Télécharger les slides  ·  🔗 Ouvrir dans un nouvel onglet

🎥 Vidéos recommandées

1. Boîte aux lettres entre processus

Une file de messages (FDM, message queue) est un mécanisme IPC qui implémente le concept de boîte aux lettres : un processus dépose un paquet, un autre vient le chercher — éventuellement plus tard, éventuellement en filtrant par catégorie.

Idée centrale Communication structurée : les données circulent sous forme de paquets identifiables et indivisibles, à la différence des tubes qui transportent un flot continu d'octets. Une lecture extraira exactement ce qu'une écriture a produit.
Paquet typé
Chaque message porte un type (long > 0). Un processus peut extraire de la file un message par son type : c'est le multiplexage.
FIFO par type
On lit toujours le message du type cherché qui a séjourné le plus longtemps dans la file (FIFO par catégorie).

Propriétés

  • Données structurées : un type de message + un message de longueur variable.
  • Possibilité d'attendre uniquement des messages d'un type donné. Sinon, le processus est bloqué (attente passive).
  • L'attente est bloquante par défaut ; on peut la désactiver avec IPC_NOWAIT (renvoie un code d'erreur si rien à lire/écrire).
  • Comme les tubes, les files de messages ont des droits d'accès Unix (rwx, rwx, rwx).
Deux implémentations cohabitent L'API Unix propose les MQ Système V (msgget / msgsnd / msgrcv / msgctl) et les POSIX MQ (mq_open / mq_send / mq_receive…). Ce cours détaille principalement la voie Système V.

2. Vue d'ensemble — la file en image

Une file de messages se laisse imaginer comme une rangée de casiers étiquetés. Les producteurs déposent à droite, les consommateurs piochent à gauche, mais chacun peut filtrer par étiquette (mtype).

Producteur A Producteur B file (FIFO par type) type 1 type 2 type 1 type 3 type 2 Conso. msgtyp=1 Conso. msgtyp=2 Conso. msgtyp=3 → msgsnd dépose un paquet (mtype, mtext) ← msgrcv extrait le plus ancien du type demandé (multiplexage)

3. Tubes vs files de messages

CritèreTubes (pipes)Files de messages
Nature des donnéesFlot d'octets continuPaquets structurés, indivisibles
Frontière entre messagesAucune (au consommateur de la trouver)Garantie : une lecture = un message émis
SélectionLecture séquentielle uniquementFiltrage par mtype (multiplexage)
OrdreFIFO globalFIFO par type
Multi-clientsDifficile (un seul flux)Naturel : N producteurs / N consommateurs
PersistanceVie liée aux processus ouvertsPersiste dans le noyau jusqu'à IPC_RMID
IdentificationDescripteur de fichierClé IPC (ftok ou IPC_PRIVATE)
DroitsPermissions UnixPermissions Unix (rwx, rwx, rwx)
Quand préférer une FDM ? Dès qu'il y a plusieurs catégories de messages, plusieurs consommateurs qui ne s'intéressent qu'à certaines catégories, ou un besoin de découplage temporel (le producteur peut écrire avant que le consommateur n'existe).

4. Structure d'un message — msgbuf

Le header <sys/msg.h> contient un modèle générique de message :

struct msgbuf {
    long mtype;     /* type of received/sent message (syscall_slong_t mtype;) */
    char mtext[];   /* text of the message */
};

C'est un modèle : on peut définir sa propre structure, pourvu qu'elle contienne :

① mtype : long > 0
Premier champ obligatoire. Entier strictement positif. Sert de critère de sélection (multiplexage).
② mtext : octets consécutifs
Second champ : suite d'octets en mémoire. Peut être un tableau, une structure, n'importe quoi de contigu.
/* Exemple : message « commande » personnalisé */
struct cmd_msg {
    long mtype;                 /* obligatoirement en premier */
    int  client_id;
    char body[256];
};

5. Obtenir une file — msgget

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

Crée (ou récupère) une file de messages. Renvoie son identifiant (rôle analogue à open pour les fichiers) ou -1 en cas d'erreur.

ArgumentRôle
key (key_t)Clé IPC unique. Obtenue par ftok(), ou clé symbolique IPC_PRIVATE (file privée, sous réserve de IPC_CREAT).
msgflg (int)Droits d'accès (souvent en octal : 0664) combinés avec les options IPC_CREAT, IPC_EXCL.

Générer une clé — ftok

key_t ftok(const char *pathname, int proj_id);
  • pathname : chemin d'un fichier existant et accessible.
  • proj_id : identifiant de projet, entier entre 0 et 255.
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>

int main(void) {
    key_t key;
    /* Générer une clé à partir d'un fichier existant et d'un identifiant de projet */
    key = ftok("/path/to/some/file", 65);  /* le fichier doit exister */
    if (key == -1) {
        perror("ftok");
        exit(1);
    }
    printf("La clé générée est : %d\n", key);
    return 0;
}
IPC_PRIVATE Quand on n'a pas besoin de partager la clé avec d'autres processus indépendants (typiquement entre parent et enfants forkés), on utilise IPC_PRIVATE à la place de ftok : le noyau alloue une file privée toute neuve.

6. Contrôler la file — msgctl

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

Effectue l'opération cmd sur la file identifiée par msqid. Renvoie 0 en cas de succès, -1 en cas d'échec.

cmdEffet
IPC_RMIDSupprime la file de messages.
IPC_STATCopie les informations de la structure interne dans *buf.
IPC_SETÉcrit certains champs de *buf dans la structure interne.
IPC_INFO, MSG_INFOInformations système sur les FDM.

La structure msqid_ds

struct msqid_ds {
    struct ipc_perm msg_perm;   /* Permissions de la file de messages */
    time_t          msg_stime;  /* Temps de la dernière réception de message */
    time_t          msg_rtime;  /* Temps de la dernière lecture de message */
    time_t          msg_ctime;  /* Temps de la dernière modification des métadonnées */
    unsigned long   msg_cbytes; /* Nombre actuel d'octets dans la file */
    unsigned long   msg_qnum;   /* Nombre actuel de messages dans la file */
    unsigned long   msg_qbytes; /* Taille maximale en octets de la file */
    pid_t           msg_lspid;  /* PID du dernier processus ayant envoyé un message */
    pid_t           msg_lrpid;  /* PID du dernier processus ayant lu un message */
};

La structure ipc_perm

Définie dans <sys/ipc.h>. Les champs configurables via IPC_SET sont mis en évidence :

struct ipc_perm {
    key_t          key;   /* Clé IPC */
    uid_t          uid;   /* Identifiant de l'utilisateur propriétaire actuel  [IPC_SET] */
    gid_t          gid;   /* Identifiant du groupe propriétaire                [IPC_SET] */
    uid_t          cuid;  /* Identifiant de l'utilisateur créateur */
    gid_t          cgid;  /* Identifiant du groupe créateur */
    mode_t         mode;  /* Mode d'accès (permissions)                        [IPC_SET] */
    unsigned short seq;   /* Numéro de séquence pour éviter les conflits de clés */
};

Exemple — inspecter une file

int main(void) {
    key_t key;
    int msqid;
    struct msqid_ds buf;

    key = ftok("/path/to/some/file", 65);

    /* Créer une file de messages avec des permissions spécifiques */
    msqid = msgget(key, 0666 | IPC_CREAT);  /* lecture/écriture pour tout le monde */
    if (msqid == -1) { perror("msgget"); exit(1); }

    /* Récupérer les informations sur la file de messages */
    if (msgctl(msqid, IPC_STAT, &buf) == -1) { perror("msgctl"); exit(1); }

    /* Afficher les permissions (mode) */
    printf("Permissions de la file de messages : %o\n", buf.msg_perm.mode);
    printf("Propriétaire : %d, Groupe : %d\n", buf.msg_perm.uid, buf.msg_perm.gid);

    return 0;
}

7. Émettre & recevoir — msgsnd / msgrcv

Émission — msgsnd

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

Dépose un message dans la file. Renvoie 0 en cas de succès, -1 en cas d'erreur.

ArgumentRôle
msqidIdentificateur de la fdm (renvoyé par msgget).
msgpPointeur sur une structure analogue à msgbuf — le message à envoyer.
msgszTaille en octets du corps du message (champ mtext).
msgflgSi non nul, peut valoir IPC_NOWAIT : si la file est pleine, l'appel ne bloque pas et retourne une erreur.

Réception — msgrcv

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

Extrait (supprime) un message de la file et le copie dans *msgp. Renvoie la taille en octets du message extrait, ou -1 en cas d'échec.

Sémantique de msgtyp
  • msgtyp > 0 : le plus ancien message de ce type est extrait.
  • msgtyp == 0 : le plus ancien message de la file, quel que soit son type.
  • msgtyp < 0 : le message extrait sera le dernier message dont le type est exactement -msgtyp.

msgflg = IPC_NOWAIT rend l'appel non bloquant : si aucun message du type attendu n'est présent, msgrcv revient immédiatement avec une erreur.

Producteur — envoie un message

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct msgbuf {
    long mtype;
    char mtext[128];
};

int main(void) {
    key_t key = ftok("/path/to/some/file", 65);
    int msqid = msgget(key, 0664 | IPC_CREAT);
    if (msqid == -1) { perror("msgget"); exit(1); }

    struct msgbuf msg;
    msg.mtype = 2;                              /* étiquette de catégorie */
    strncpy(msg.mtext, "Bonjour file !", sizeof msg.mtext);

    if (msgsnd(msqid, &msg, strlen(msg.mtext) + 1, 0) == -1) {
        perror("msgsnd");
        exit(1);
    }
    printf("Message de type %ld envoyé.\n", msg.mtype);
    return 0;
}

Consommateur — filtre par mtype

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>

struct msgbuf {
    long mtype;
    char mtext[128];
};

int main(void) {
    key_t key = ftok("/path/to/some/file", 65);
    int msqid = msgget(key, 0664);              /* la file doit exister */
    if (msqid == -1) { perror("msgget"); exit(1); }

    struct msgbuf msg;
    /* On ne s'intéresse qu'aux messages de type 2 : sélection par mtype */
    ssize_t n = msgrcv(msqid, &msg, sizeof msg.mtext, 2, 0);
    if (n == -1) { perror("msgrcv"); exit(1); }

    printf("Reçu (type %ld, %zd o) : %s\n", msg.mtype, n, msg.mtext);
    return 0;
}
Multiplexage En passant msgtyp = 2, ce consommateur ignore les messages de type 1, 3, … qui restent dans la file pour d'autres consommateurs. C'est l'avantage clé sur un tube partagé.

8. Commandes shell — ipcs & ipcrm

Deux commandes essentielles administrent les IPC Système V :

ipcs
Consulte les tables IPC du système : files de messages, segments de mémoire partagée, sémaphores — avec clé IPC en hexa, identifiant, propriétaire, permissions octales, taille, attachements, état.
ipcrm
Supprime une entrée dans l'une des tables (file, segment partagé ou sémaphore). Indispensable pour nettoyer après plantage : les objets IPC persistent au-delà des processus.
Persistance noyau Une file de messages survit à la fin du processus qui l'a créée. Sans msgctl(msqid, IPC_RMID, NULL) ou ipcrm, elle reste dans le noyau — et finit par saturer les limites système.

9. Les files de messages POSIX

Les POSIX MQ ont été introduites pour standardiser les MQ Système V de AT&T. Contrairement aux tubes et aux sockets, elles utilisent les modules « temps réel » du noyau — d'où leur usage industriel pour des informations importantes asynchrones mais réactives.

Principes

  • Les MQ fonctionnent comme un service de gestion de files : messages à priorités variables, les plus prioritaires et les plus anciens sont lus en premier.
  • Files approvisionnées par un ou plusieurs processus, lues par un ou plusieurs processus.
  • Des propriétés sont locales à la file (ex. nombre max de messages) ou globales au système (ex. priorité max).
  • Messages de longueur maximale fixe → implémentation simplifiée (buffer ou chaîne de taille fixe).
  • Le nom d'une MQ doit commencer par /, suivi de caractères alphanumériques.
  • Servent à transférer des messages courts entre plusieurs processus. Un processus peut lire ses propres messages.
  • Lecture destructrice : un message lu est retiré de la file.
  • La file extrait automatiquement le message le plus prioritaire le plus anciennement déposé. La priorité est fixée à l'écriture.
  • POSIX impose au minimum 32 niveaux de priorité ; convention : 0 pour les messages normaux, supérieurs pour les urgents.

Les 5 prototypes principaux

mqd_t   mq_open   (const char *, int, ...);
ssize_t mq_receive(mqd_t, char *, size_t, unsigned *);
int     mq_send   (mqd_t, const char *, size_t, unsigned);
int     mq_close  (mqd_t);
int     mq_unlink (const char *);
Système V vs POSIX en un coup d'œil Les fonctions POSIX sont très similaires à celles des autres IPC : ouverture/fermeture, lecture/écriture. Différence principale : messages de longueurs fixes + numéro de priorité (au lieu d'un mtype de sélection).

Réviser le chapitre

❓ Q/R — vérifier ta compréhension

En quoi une file de messages diffère-t-elle d'un tube ?
Un tube transporte un flot continu d'octets sans frontière de message ; une file transporte des paquets typés et indivisibles. Une lecture extrait exactement le produit d'une écriture.
À quoi sert le champ mtype ?
À multiplexer la file : chaque consommateur peut filtrer les messages par leur type (msgtyp dans msgrcv). Doit être un long strictement positif.
Comment obtient-on l'identifiant d'une file ?
Par msgget(key, msgflg). La clé est obtenue avec ftok (chemin + proj_id) ou via IPC_PRIVATE pour une file privée. msgflg contient les droits + IPC_CREAT / IPC_EXCL.
Que se passe-t-il si aucun message du type demandé n'est présent ?
Par défaut, msgrcv bloque (attente passive). Avec IPC_NOWAIT, il revient immédiatement avec un code d'erreur.
Que vaut msgtyp pour lire « n'importe quel message » ?
msgtyp = 0 : on extrait le plus ancien message de la file, quel que soit son type.
Et pour lire le dernier message d'un type donné ?
msgtyp < 0 : on extrait le dernier message dont le type est exactement -msgtyp.
Comment supprimer une file après usage ?
msgctl(msqid, IPC_RMID, NULL) côté programme, ou la commande shell ipcrm. Sans ça, la file persiste dans le noyau.
Pourquoi ipcs est-il utile ?
Pour inspecter les IPC Système V actifs (files, segments partagés, sémaphores) avec leurs clés, identifiants, propriétaire, permissions, taille et état.
Qu'est-ce qui différencie POSIX MQ et Système V MQ ?
POSIX MQ : modules temps réel du noyau, messages de longueur fixe, priorités (≥ 32 niveaux), noms commençant par /. Système V : longueur variable, sélection par mtype, identification par clé IPC.
Pourquoi POSIX MQ ne convient-il pas à de gros messages ?
Elles servent essentiellement à transférer des messages courts ; la longueur max est fixée par la file et le système — idéal pour signalisation réactive, pas pour du transfert volumineux.

🃏 Flashcards éclair

Clique pour retourner.

FDM en 1 phrase

C'est quoi ?

tourne →
Une boîte aux lettres IPC où les processus échangent des paquets typés et indivisibles, FIFO par type.

Tubes vs FDM

Différence clé.

tourne →
Tube : flot d'octets, pas de frontière, pas de sélection.
FDM : paquets structurés, filtrage par mtype.

Header & struct

Où ? Quoi ?

tourne →
<sys/msg.h>
struct msgbuf {
  long mtype;
  char mtext[];
};

mtype

Type et contrainte.

tourne →
long strictement positif. Premier champ obligatoire. Critère de sélection (multiplexage).

msgget

Signature.

tourne →
int msgget(key_t key,
           int msgflg);

ftok

Arguments.

tourne →
ftok(pathname, proj_id) · fichier existant + entier 0–255key_t.

IPC_PRIVATE

Quand ?

tourne →
Clé symbolique pour créer une file privée (typiquement entre parent et enfants fork) — avec IPC_CREAT.

msgsnd

Signature + retour.

tourne →
int msgsnd(int msqid,
   const void *msgp,
   size_t msgsz, int msgflg);
/* 0 ok, -1 err */

msgrcv

Signature + retour.

tourne →
ssize_t msgrcv(int msqid,
   void *msgp, size_t msgsz,
   long msgtyp, int msgflg);
/* taille ok, -1 err */

msgtyp

3 cas.

tourne →
> 0 : plus ancien de ce type
= 0 : plus ancien, tous types
< 0 : dernier de type -msgtyp

IPC_NOWAIT

Effet.

tourne →
Rend msgsnd / msgrcv non bloquants ; renvoient une erreur si file pleine / pas de message du type attendu.

msgctl — cmd

4 valeurs.

tourne →
IPC_RMID (supprimer) · IPC_STAT (lire) · IPC_SET (écrire) · IPC_INFO / MSG_INFO

ipcs / ipcrm

Rôle.

tourne →
ipcs : consulter les tables IPC. ipcrm : supprimer une entrée (file, segment, sémaphore).

POSIX MQ — 5 fcts

Citer.

tourne →
mq_open, mq_send,
mq_receive,
mq_close, mq_unlink

POSIX MQ — spécif.

3 traits.

tourne →
① Messages de longueur fixe
Priorités (≥ 32 niveaux, 0 = normal)
③ Noms commençant par / + alphanum.

✎ Quiz éclair

test rapide · 7 questions
0 / 7
1.Une file de messages garantit que :
  • Les données arrivent comme un flot d'octets
  • Un seul processus peut lire à la fois
  • Une lecture extrait exactement le produit d'une écriture
  • Le noyau ordonne les messages par taille
Les paquets sont indivisibles, à la différence d'un tube.
2.Le champ mtype de msgbuf doit être :
  • Un int quelconque
  • Un long strictement positif, placé en premier
  • Une chaîne de caractères
  • Un unsigned char compris entre 0 et 255
Sert de critère de sélection (multiplexage).
3.Pour créer une file privée à un parent et ses enfants fork :
  • Utiliser ftok avec un fichier temporaire
  • Passer la clé 0
  • Passer la clé -1
  • Utiliser IPC_PRIVATE avec IPC_CREAT
La clé symbolique IPC_PRIVATE demande au noyau une file fraîche.
4.msgrcv(msqid, &m, sz, 0, 0) extrait :
  • Le dernier message de type 0
  • Aucun message (erreur)
  • Le plus ancien message de la file, quel que soit son type
  • Le message le plus prioritaire
msgtyp == 0 : pas de filtrage, FIFO global.
5.Le drapeau IPC_NOWAIT sert à :
  • Forcer la suppression de la file
  • Rendre msgsnd / msgrcv non bloquants
  • Désactiver le filtrage par mtype
  • Augmenter la priorité du message
Sans IPC_NOWAIT, le défaut est bloquant (attente passive).
6.Pour supprimer la file depuis le code :
  • msgctl(msqid, IPC_RMID, NULL)
  • close(msqid)
  • msgsnd(msqid, NULL, 0, IPC_RMID)
  • unlink(msqid)
Sans cela (ou un ipcrm shell), la file persiste dans le noyau.
7.Différence principale entre POSIX MQ et MQ Système V :
  • POSIX MQ utilisent des descripteurs de fichier classiques
  • POSIX MQ n'autorisent qu'un seul lecteur par file
  • POSIX MQ acceptent des messages de longueur variable
  • POSIX MQ travaillent avec des messages de longueur fixe et des priorités
≥ 32 niveaux de priorité ; convention : 0 = normal, > 0 = urgent.

📌 À retenir

  • FDM = boîte aux lettres IPC : paquets typés et indivisibles, à la différence des tubes (flot continu).
  • Une lecture extrait exactement le produit d'une écriture.
  • FIFO par type : on lit le plus ancien message du type cherché.
  • Attente bloquante par défaut ; non bloquante avec IPC_NOWAIT.
  • Droits Unix (rwx, rwx, rwx). Persistance dans le noyau → penser à supprimer.
  • Header <sys/msg.h> · structure modèle msgbuf { long mtype; char mtext[]; }.
  • mtype est un long strictement positif placé en premier — critère de multiplexage.
  • msgget(key, msgflg) → identifiant. Clé via ftok(path, proj_id 0–255) ou IPC_PRIVATE.
  • Options : IPC_CREAT, IPC_EXCL + droits octaux (0664, 0666…).
  • msgsnd(msqid, msgp, msgsz, msgflg) dépose un message. Retour 0 / -1.
  • msgrcv(msqid, msgp, msgsz, msgtyp, msgflg) extrait ; retour = taille en octets.
  • msgtyp : > 0 plus ancien de ce type · = 0 plus ancien tous types · < 0 dernier de type -msgtyp.
  • msgctl(msqid, cmd, buf) avec IPC_RMID / IPC_STAT / IPC_SET / IPC_INFO.
  • Outils shell : ipcs (lister), ipcrm (supprimer).
  • POSIX MQ : noms en /, messages de longueur fixe, priorités (≥ 32 niveaux), temps réel — mq_open / mq_send / mq_receive / mq_close / mq_unlink.