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.
📄 Ressources du cours
🎥 Vidéos recommandées
-
🇫🇷
programmation client/serveur: introduction
yassine bouamar · 12:42 · 22k vues — نقدم لكم الدرس الأول من برمجة المستخدم والخادم باستعمال لغة vb.net وتقنية ado.net دائما على مدونة دروسي:www.dorousy.com
-
🇫🇷
Part 3- Programmation Réseaux et Systèmes Distribuées-Serveur Multi Threads
Professeur Mohamed YOUSSFI · 40:07 · 14k vues — Cette série de vidéos présente les bases de la programmation réseaux et des systèmes distribués. Elle inclut les éléments suivants :- Concepts de base de la ...
-
🇬🇧
TCP Client Server Implementation in C | Socket Programming in C
Idiot Developer · 21:09 · 113k vues — This video will implement TCP client-server architecture in the C programming language, where both the client and server can communicate with each other.TCP ...
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.
Chaque message porte un type (long > 0). Un processus peut extraire de la file un message par son type : c'est le multiplexage.
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).
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).
3. Tubes vs files de messages
| Critère | Tubes (pipes) | Files de messages |
|---|---|---|
| Nature des données | Flot d'octets continu | Paquets structurés, indivisibles |
| Frontière entre messages | Aucune (au consommateur de la trouver) | Garantie : une lecture = un message émis |
| Sélection | Lecture séquentielle uniquement | Filtrage par mtype (multiplexage) |
| Ordre | FIFO global | FIFO par type |
| Multi-clients | Difficile (un seul flux) | Naturel : N producteurs / N consommateurs |
| Persistance | Vie liée aux processus ouverts | Persiste dans le noyau jusqu'à IPC_RMID |
| Identification | Descripteur de fichier | Clé IPC (ftok ou IPC_PRIVATE) |
| Droits | Permissions Unix | Permissions Unix (rwx, rwx, rwx) |
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 :
Premier champ obligatoire. Entier strictement positif. Sert de critère de sélection (multiplexage).
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.
| Argument | Rô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;
}
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.
cmd | Effet |
|---|---|
IPC_RMID | Supprime la file de messages. |
IPC_STAT | Copie les informations de la structure interne dans *buf. |
IPC_SET | Écrit certains champs de *buf dans la structure interne. |
IPC_INFO, MSG_INFO… | Informations 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.
| Argument | Rôle |
|---|---|
msqid | Identificateur de la fdm (renvoyé par msgget). |
msgp | Pointeur sur une structure analogue à msgbuf — le message à envoyer. |
msgsz | Taille en octets du corps du message (champ mtext). |
msgflg | Si 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.
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;
}
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 :
ipcsConsulte 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.
ipcrmSupprime 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.
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 :
0pour 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 *);
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 ?
À quoi sert le champ mtype ?
msgtyp dans msgrcv). Doit être un long strictement positif.Comment obtient-on l'identifiant d'une file ?
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 ?
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 ?
Qu'est-ce qui différencie POSIX MQ et Système V MQ ?
/. Système V : longueur variable, sélection par mtype, identification par clé IPC.Pourquoi POSIX MQ ne convient-il pas à de gros messages ?
🃏 Flashcards éclair
Clique pour retourner.
FDM en 1 phrase
C'est quoi ?
tourne →Tubes vs FDM
Différence clé.
tourne →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–255 → key_t.IPC_PRIVATE
Quand ?
tourne →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, tous types
< 0 : dernier de type
-msgtypIPC_NOWAIT
Effet.
tourne →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_INFOipcs / 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_unlinkPOSIX MQ — spécif.
3 traits.
tourne →② Priorités (≥ 32 niveaux, 0 = normal)
③ Noms commençant par
/ + alphanum.✎ Quiz éclair
mtype de msgbuf doit être :fork :IPC_PRIVATE demande au noyau une file fraîche.msgrcv(msqid, &m, sz, 0, 0) extrait :msgtyp == 0 : pas de filtrage, FIFO global.IPC_NOWAIT sert à :ipcrm shell), la file persiste dans le noyau.📌 À 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èlemsgbuf { long mtype; char mtext[]; }. mtypeest unlongstrictement positif placé en premier — critère de multiplexage.msgget(key, msgflg)→ identifiant. Clé viaftok(path, proj_id 0–255)ouIPC_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:> 0plus ancien de ce type ·= 0plus ancien tous types ·< 0dernier de type-msgtyp.msgctl(msqid, cmd, buf)avecIPC_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.