Files d'attente de messages
Pourquoi avons-nous besoin de files d'attente de messages alors que nous avons déjà la mémoire partagée? Ce serait pour plusieurs raisons, essayons de diviser cela en plusieurs points pour simplifier -
Tel que compris, une fois que le message est reçu par un processus, il ne sera plus disponible pour aucun autre processus. Alors que dans la mémoire partagée, les données sont disponibles pour l'accès de plusieurs processus.
Si nous voulons communiquer avec de petits formats de message.
Les données de mémoire partagée doivent être protégées par synchronisation lorsque plusieurs processus communiquent en même temps.
La fréquence d'écriture et de lecture à l'aide de la mémoire partagée est élevée, il serait alors très complexe de mettre en œuvre la fonctionnalité. Ne vaut pas en ce qui concerne l'utilisation dans ce genre de cas.
Que se passe-t-il si tous les processus n'ont pas besoin d'accéder à la mémoire partagée mais que très peu de processus en ont seulement besoin, il serait préférable de l'implémenter avec des files d'attente de messages.
Si nous voulons communiquer avec différents paquets de données, disons que le processus A envoie le type de message 1 au processus B, le type de message 10 au processus C et le type de message 20 au traitement D. Dans ce cas, il est plus simple à mettre en œuvre avec des files d'attente de messages. Pour simplifier le type de message donné en 1, 10, 20, il peut être 0 ou + ve ou –ve comme indiqué ci-dessous.
Bien entendu, l'ordre de la file d'attente des messages est FIFO (First In First Out). Le premier message inséré dans la file d'attente est le premier à être récupéré.
L'utilisation de la mémoire partagée ou des files d'attente de messages dépend des besoins de l'application et de l'efficacité avec laquelle elle peut être utilisée.
La communication à l'aide de files d'attente de messages peut se produire des manières suivantes:
Écriture dans la mémoire partagée par un processus et lecture de la mémoire partagée par un autre processus. Comme nous le savons, la lecture peut également être effectuée avec plusieurs processus.
Écriture dans la mémoire partagée par un processus avec différents paquets de données et lecture de celle-ci par plusieurs processus, c'est-à-dire selon le type de message.
Après avoir vu certaines informations sur les files d'attente de messages, il est maintenant temps de vérifier l'appel système (System V) qui prend en charge les files d'attente de messages.
Pour effectuer une communication à l'aide de files d'attente de messages, procédez comme suit:
Step 1 - Créez une file d'attente de messages ou connectez-vous à une file d'attente de messages déjà existante (msgget ())
Step 2 - Ecrire dans la file d'attente des messages (msgsnd ())
Step 3 - Lire depuis la file d'attente des messages (msgrcv ())
Step 4 - Effectuer des opérations de contrôle sur la file d'attente des messages (msgctl ())
Maintenant, vérifions la syntaxe et certaines informations sur les appels ci-dessus.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg)
Cet appel système crée ou alloue une file d'attente de messages System V. Les arguments suivants doivent être passés -
Le premier argument, clé, reconnaît la file d'attente des messages. La clé peut être une valeur arbitraire ou une valeur qui peut être dérivée de la fonction de bibliothèque ftok ().
Le deuxième argument, shmflg, spécifie le ou les indicateurs de file d'attente de messages requis tels que IPC_CREAT (création d'une file d'attente de messages s'il n'existe pas) ou IPC_EXCL (utilisé avec IPC_CREAT pour créer la file d'attente de messages et l'appel échoue, si la file d'attente de messages existe déjà). Vous devez également passer les autorisations.
Note - Reportez-vous aux sections précédentes pour plus de détails sur les autorisations.
Cet appel renverrait un identifiant de file d'attente de messages valide (utilisé pour d'autres appels de la file d'attente de messages) en cas de succès et -1 en cas d'échec. Pour connaître la cause de l'échec, vérifiez avec la variable errno ou la fonction perror ().
Diverses erreurs concernant cet appel sont EACCESS (autorisation refusée), EEXIST (la file d'attente existe déjà ne peut pas être créée), ENOENT (la file d'attente n'existe pas), ENOMEM (pas assez de mémoire pour créer la file d'attente), etc.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
Cet appel système envoie / ajoute un message dans la file d'attente de messages (System V). Les arguments suivants doivent être passés -
Le premier argument, msgid, reconnaît la file d'attente de messages, c'est-à-dire l'identificateur de file d'attente de messages. La valeur de l'identifiant est reçue lors du succès de msgget ()
Le deuxième argument, msgp, est le pointeur vers le message, envoyé à l'appelant, défini dans la structure de la forme suivante -
struct msgbuf {
long mtype;
char mtext[1];
};
La variable mtype est utilisée pour communiquer avec différents types de messages, expliqués en détail dans l'appel msgrcv (). La variable mtext est un tableau ou une autre structure dont la taille est spécifiée par msgsz (valeur positive). Si le champ mtext n'est pas mentionné, alors il est considéré comme un message de taille zéro, ce qui est autorisé.
Le troisième argument, msgsz, est la taille du message (le message doit se terminer par un caractère nul)
Le quatrième argument, msgflg, indique certains indicateurs tels que IPC_NOWAIT (retourne immédiatement lorsqu'aucun message n'est trouvé dans la file d'attente ou MSG_NOERROR (tronque le texte du message, si plus de msgsz octets)
Cet appel renverrait 0 en cas de succès et -1 en cas d'échec. Pour connaître la cause de l'échec, vérifiez avec la variable errno ou la fonction perror ().
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msgid, const void *msgp, size_t msgsz, long msgtype, int msgflg)
Cet appel système récupère le message de la file d'attente de messages (System V). Les arguments suivants doivent être passés -
Le premier argument, msgid, reconnaît la file d'attente de messages, c'est-à-dire l'identifiant de la file d'attente de messages. La valeur de l'identifiant est reçue lors du succès de msgget ()
Le deuxième argument, msgp, est le pointeur du message reçu de l'appelant. Il est défini dans la structure de la forme suivante -
struct msgbuf {
long mtype;
char mtext[1];
};
La variable mtype est utilisée pour communiquer avec différents types de messages. La variable mtext est un tableau ou une autre structure dont la taille est spécifiée par msgsz (valeur positive). Si le champ mtext n'est pas mentionné, alors il est considéré comme un message de taille zéro, ce qui est autorisé.
Le troisième argument, msgsz, est la taille du message reçu (le message doit se terminer par un caractère nul)
Le quatrième argument, msgtype, indique le type de message -
If msgtype is 0 - Lit le premier message reçu dans la file d'attente
If msgtype is +ve - Lit le premier message de la file d'attente de type msgtype (si msgtype vaut 10, alors lit uniquement le premier message de type 10 même si d'autres types peuvent être dans la file d'attente au début)
If msgtype is –ve - Lit le premier message de type le plus bas inférieur ou égal à la valeur absolue du type de message (par exemple, si msgtype est -5, alors il lit le premier message de type inférieur à 5, c'est-à-dire, type de message de 1 à 5)
Le cinquième argument, msgflg, indique certains indicateurs tels que IPC_NOWAIT (retourne immédiatement lorsqu'aucun message n'est trouvé dans la file d'attente ou MSG_NOERROR (tronque le texte du message si plus de msgsz octets)
Cet appel renverrait le nombre d'octets réellement reçus dans le tableau mtext en cas de succès et -1 en cas d'échec. Pour connaître la cause de l'échec, vérifiez avec la variable errno ou la fonction perror ().
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msgid, int cmd, struct msqid_ds *buf)
Cet appel système effectue des opérations de contrôle de la file d'attente de messages (System V). Les arguments suivants doivent être passés -
Le premier argument, msgid, reconnaît la file d'attente de messages, c'est-à-dire l'identifiant de la file d'attente de messages. La valeur de l'identifiant est reçue lors du succès de msgget ()
Le deuxième argument, cmd, est la commande pour effectuer l'opération de contrôle requise sur la file d'attente de messages. Les valeurs valides pour cmd sont -
IPC_STAT- Copie les informations des valeurs courantes de chaque membre de la structure msqid_ds dans la structure transmise pointée par buf. Cette commande nécessite une autorisation de lecture sur la file d'attente des messages.
IPC_SET - Définit l'ID utilisateur, l'ID de groupe du propriétaire, les autorisations, etc. pointés par la structure buf.
IPC_RMID - Supprime immédiatement la file d'attente des messages.
IPC_INFO - Renvoie des informations sur les limites et les paramètres de la file d'attente de messages dans la structure pointée par buf, qui est de type struct msginfo
MSG_INFO - Renvoie une structure msginfo contenant des informations sur les ressources système consommées par la file d'attente de messages.
Le troisième argument, buf, est un pointeur vers la structure de file d'attente de messages nommée struct msqid_ds. Les valeurs de cette structure seraient utilisées pour définir ou obtenir selon cmd.
Cet appel renverrait la valeur en fonction de la commande passée. Le succès de IPC_INFO et MSG_INFO ou MSG_STAT renvoie l'index ou l'identifiant de la file de messages ou 0 pour les autres opérations et -1 en cas d'échec. Pour connaître la cause de l'échec, vérifiez avec la variable errno ou la fonction perror ().
Après avoir vu les informations de base et les appels système concernant les files d'attente de messages, il est maintenant temps de vérifier avec un programme.
Voyons la description avant de regarder le programme -
Step 1 - Créez deux processus, l'un pour l'envoi dans la file d'attente de messages (msgq_send.c) et l'autre pour la récupération de la file d'attente de messages (msgq_recv.c)
Step 2- Création de la clé, en utilisant la fonction ftok (). Pour cela, le fichier msgq.txt est initialement créé pour obtenir une clé unique.
Step 3 - Le processus d'envoi effectue les opérations suivantes.
Lit la chaîne d'entrée de l'utilisateur
Supprime la nouvelle ligne, si elle existe
Envoie dans la file d'attente des messages
Répète le processus jusqu'à la fin de l'entrée (CTRL + D)
Une fois la fin de l'entrée reçue, envoie le message «fin» pour signifier la fin du processus
Step 4 - Dans le processus de réception, effectue les opérations suivantes.
- Lit le message dans la file d'attente
- Affiche la sortie
- Si le message reçu est «end», termine le processus et quitte
Pour simplifier, nous n'utilisons pas le type de message pour cet exemple. En outre, un processus écrit dans la file d'attente et un autre processus lit dans la file d'attente. Cela peut être étendu au besoin, c'est-à-dire que, idéalement, un processus écrirait dans la file d'attente et plusieurs processus liraient dans la file d'attente.
Maintenant, vérifions le processus (envoi du message dans la file d'attente) - Fichier: msgq_send.c
/* Filename: msgq_send.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PERMS 0644
struct my_msgbuf {
long mtype;
char mtext[200];
};
int main(void) {
struct my_msgbuf buf;
int msqid;
int len;
key_t key;
system("touch msgq.txt");
if ((key = ftok("msgq.txt", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, PERMS | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
printf("message queue: ready to send messages.\n");
printf("Enter lines of text, ^D to quit:\n");
buf.mtype = 1; /* we don't really care in this case */
while(fgets(buf.mtext, sizeof buf.mtext, stdin) != NULL) {
len = strlen(buf.mtext);
/* remove newline at end, if it exists */
if (buf.mtext[len-1] == '\n') buf.mtext[len-1] = '\0';
if (msgsnd(msqid, &buf, len+1, 0) == -1) /* +1 for '\0' */
perror("msgsnd");
}
strcpy(buf.mtext, "end");
len = strlen(buf.mtext);
if (msgsnd(msqid, &buf, len+1, 0) == -1) /* +1 for '\0' */
perror("msgsnd");
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
printf("message queue: done sending messages.\n");
return 0;
}
Étapes de compilation et d'exécution
message queue: ready to send messages.
Enter lines of text, ^D to quit:
this is line 1
this is line 2
message queue: done sending messages.
Voici le code du processus de réception de message (récupération du message de la file d'attente) - Fichier: msgq_recv.c
/* Filename: msgq_recv.c */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PERMS 0644
struct my_msgbuf {
long mtype;
char mtext[200];
};
int main(void) {
struct my_msgbuf buf;
int msqid;
int toend;
key_t key;
if ((key = ftok("msgq.txt", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, PERMS)) == -1) { /* connect to the queue */
perror("msgget");
exit(1);
}
printf("message queue: ready to receive messages.\n");
for(;;) { /* normally receiving never ends but just to make conclusion
/* this program ends wuth string of end */
if (msgrcv(msqid, &buf, sizeof(buf.mtext), 0, 0) == -1) {
perror("msgrcv");
exit(1);
}
printf("recvd: \"%s\"\n", buf.mtext);
toend = strcmp(buf.mtext,"end");
if (toend == 0)
break;
}
printf("message queue: done receiving messages.\n");
system("rm msgq.txt");
return 0;
}
Étapes de compilation et d'exécution
message queue: ready to receive messages.
recvd: "this is line 1"
recvd: "this is line 2"
recvd: "end"
message queue: done receiving messages.