System V Message Queues sous Linux

Ce forum est dédié à apprendre le développement de programmes user mode sur Linux

Moderator: Rick

Post Reply
Hydraxx
Site Admin
Posts: 114
Joined: Mon Jan 12, 2026 4:04 pm
Location: France
Contact:

System V Message Queues sous Linux

Post by Hydraxx »

System V Message Queues sous Linux

Objectif

Les System V message queues permettent à plusieurs processus d'échanger des messages structurés via une file maintenue par le kernel.

Contrairement à un pipe, les frontières des messages sont conservées.

1. Principe

Code: Select all

Processus A
    |
    | msgsnd()
    v
[ FILE DE MESSAGES KERNEL ]
    |
    | msgrcv()
    v
Processus B
Une file contient plusieurs messages indépendants.

Chaque message possède :
  • un type ;
  • des données.
2. En-têtes

Code: Select all

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
3. Création ou ouverture : msgget()

Prototype :

Code: Select all

int msgget(key_t key, int msgflg);
Retour :
  • identifiant de queue en cas de succès ;
  • -1 en cas d'erreur.
Exemple :

Code: Select all

key_t key = ftok("/tmp/msg.key", 'M');

int msqid = msgget(key, IPC_CREAT | 0600);

if (msqid == -1) {
    perror("msgget");
}
Création stricte :

Code: Select all

int msqid = msgget(key, IPC_CREAT | IPC_EXCL | 0600);
4. Structure d'un message

La structure passée à msgsnd() et msgrcv() commence obligatoirement par un long représentant le type.

Exemple :

Code: Select all

struct message {
    long mtype;
    char text[256];
};
mtype doit être strictement positif pour les messages envoyés.

Le reste de la structure constitue le corps du message.

5. Envoi : msgsnd()

Prototype :

Code: Select all

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

Code: Select all

struct message msg;

msg.mtype = 1;
strcpy(msg.text, "Bonjour");

if (msgsnd(msqid, &msg, strlen(msg.text) + 1, 0) == -1) {
    perror("msgsnd");
}
msgsz correspond à la taille du corps du message, pas à la taille totale incluant mtype.

Exemple sûr :

Code: Select all

msgsnd(msqid, &msg, sizeof(msg.text), 0);
6. Blocage de msgsnd()

Si la queue est pleine, msgsnd() peut bloquer jusqu'à ce qu'il y ait suffisamment de place.

Pour demander un comportement non bloquant :

Code: Select all

IPC_NOWAIT
Exemple :

Code: Select all

msgsnd(msqid, &msg, sizeof(msg.text), IPC_NOWAIT);
Si l'envoi ne peut pas être effectué immédiatement, l'appel échoue typiquement avec EAGAIN.

7. Réception : msgrcv()

Prototype :

Code: Select all

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

Code: Select all

struct message msg;

ssize_t n = msgrcv(msqid,
                   &msg,
                   sizeof(msg.text),
                   0,
                   0);

if (n == -1) {
    perror("msgrcv");
}
8. Sélection avec msgtyp

Le paramètre msgtyp permet de sélectionner quels messages doivent être reçus.

msgtyp == 0

Retourne le premier message de la queue.

Code: Select all

msgrcv(msqid, &msg, sizeof(msg.text), 0, 0);
msgtyp > 0

Retourne le premier message correspondant exactement au type demandé.

Code: Select all

msgrcv(msqid, &msg, sizeof(msg.text), 5, 0);
Ici, seuls les messages de type 5 sont recherchés.

msgtyp < 0

Sélection spéciale basée sur la plus petite valeur de type satisfaisant la limite donnée.

Cette possibilité peut être utilisée pour implémenter une forme de priorité.

9. IPC_NOWAIT avec msgrcv()

Par défaut, si aucun message correspondant n'existe, msgrcv() peut bloquer.

Avec :

Code: Select all

IPC_NOWAIT
l'appel retourne immédiatement si aucun message correspondant n'est disponible.

10. MSG_NOERROR

Si le buffer fourni à msgrcv() est plus petit que le message :
  • sans MSG_NOERROR : erreur ;
  • avec MSG_NOERROR : le message peut être tronqué.
Exemple :

Code: Select all

msgrcv(msqid,
       &msg,
       sizeof(msg.text),
       0,
       MSG_NOERROR);
11. Suppression d'un message

Lorsqu'un message est reçu avec succès via msgrcv(), il est normalement retiré de la queue.

La file agit donc comme une file de messages consommables.

12. Contrôle : msgctl()

Prototype :

Code: Select all

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

Code: Select all

IPC_STAT
IPC_SET
IPC_RMID
13. IPC_RMID

Suppression :

Code: Select all

if (msgctl(msqid, IPC_RMID, NULL) == -1) {
    perror("msgctl IPC_RMID");
}
Les processus bloqués sur la queue peuvent être réveillés avec une erreur lorsque l'objet est supprimé.

14. IPC_STAT

Récupération des informations :

Code: Select all

struct msqid_ds ds;

if (msgctl(msqid, IPC_STAT, &ds) == -1) {
    perror("msgctl IPC_STAT");
}
La structure contient notamment des informations sur :
  • permissions ;
  • nombre de messages ;
  • nombre d'octets ;
  • PID du dernier émetteur ;
  • PID du dernier récepteur ;
  • timestamps ;
  • limites de la queue.
15. IPC_SET

IPC_SET permet de modifier certains champs autorisés de la structure associée à la queue.

Cela peut notamment concerner certaines permissions ou limites, selon les droits du processus.

16. Modèle client/serveur

Deux modèles classiques existent.

Une seule queue

Code: Select all

Client ---> queue commune ---> Serveur
Serveur ---> même queue ---> Client
Les types de messages permettent de distinguer requêtes et réponses.

Exemple :

Code: Select all

type 1       = requête serveur
type 100+PID = réponse pour un client
Une queue serveur + une queue par client

Code: Select all

Client ----> Queue serveur ----> Serveur

Serveur ----> Queue client ----> Client
Ce modèle facilite la séparation des réponses.

17. Exemple minimal complet

Création :

Code: Select all

key_t key = ftok("/tmp/msg.key", 'M');

int msqid = msgget(key, IPC_CREAT | 0600);
if (msqid == -1)
    perror("msgget");
Envoi :

Code: Select all

struct message {
    long mtype;
    char text[128];
};

struct message msg;

msg.mtype = 1;
snprintf(msg.text, sizeof(msg.text), "hello");

if (msgsnd(msqid, &msg, strlen(msg.text) + 1, 0) == -1)
    perror("msgsnd");
Réception :

Code: Select all

struct message msg;

if (msgrcv(msqid, &msg, sizeof(msg.text), 1, 0) == -1)
    perror("msgrcv");

printf("%s\n", msg.text);
Nettoyage :

Code: Select all

msgctl(msqid, IPC_RMID, NULL);
18. Différence avec un pipe

Pipe :

Code: Select all

flux d'octets
pas de notion native de message
read() lit une quantité d'octets
Message queue :

Code: Select all

messages séparés
type associé à chaque message
sélection possible par type
objet persistant dans le kernel
19. Limites

Le kernel impose des limites sur :
  • taille maximale d'un message ;
  • quantité totale de données dans une queue ;
  • nombre de queues ;
  • ressources globales utilisées.
Sous Linux, ces limites peuvent être consultées ou configurées via les mécanismes du noyau correspondants.

Il n'est pas utile de mémoriser leurs valeurs exactes.

20. Inspection

Afficher les queues :

Code: Select all

ipcs -q
Afficher les informations System V IPC :

Code: Select all

cat /proc/sysvipc/msg
Supprimer manuellement :

Code: Select all

ipcrm -q <msqid>
21. Erreurs importantes

Cas fréquents :
  • EEXIST : IPC_CREAT | IPC_EXCL et queue déjà existante.
  • EACCES : permissions insuffisantes.
  • EAGAIN : IPC_NOWAIT et opération impossible immédiatement.
  • EINTR : appel bloquant interrompu par un signal.
  • EIDRM : objet supprimé pendant qu'un processus attendait dessus.
  • EINVAL : identifiant ou paramètres invalides.
22. Avantages
  • frontières des messages conservées ;
  • communication entre processus indépendants ;
  • sélection des messages par type ;
  • pas besoin de gérer soi-même un protocole de framing.
23. Inconvénients
  • API historique et assez lourde ;
  • objets persistants à nettoyer explicitement ;
  • limites kernel ;
  • identifiants System V spécifiques ;
  • moins naturelle que sockets ou POSIX message queues pour beaucoup de nouveaux projets.
24. API à retenir

Code: Select all

msgget()   // créer / ouvrir
msgsnd()   // envoyer
msgrcv()   // recevoir
msgctl()   // contrôler / supprimer
25. Carte mentale

Code: Select all

key / ftok
    |
    v
msgget()
    |
    v
msqid
    |
    +----> msgsnd()
    |
    +----> msgrcv()
    |
    +----> msgctl()
             |
             +-- IPC_STAT
             +-- IPC_SET
             +-- IPC_RMID

Who is online

Users browsing this forum: No registered users and 1 guest