Nachrichtenwarteschlangen
Warum benötigen wir Nachrichtenwarteschlangen, wenn wir bereits über den gemeinsam genutzten Speicher verfügen? Es wäre aus mehreren Gründen, lassen Sie uns versuchen, dies zur Vereinfachung in mehrere Punkte zu unterteilen -
Sobald die Nachricht von einem Prozess empfangen wurde, ist sie für keinen anderen Prozess mehr verfügbar. Während im gemeinsam genutzten Speicher die Daten für mehrere Prozesse verfügbar sind.
Wenn wir mit kleinen Nachrichtenformaten kommunizieren wollen.
Shared Memory-Daten müssen durch Synchronisation geschützt werden, wenn mehrere Prozesse gleichzeitig kommunizieren.
Die Häufigkeit des Schreibens und Lesens unter Verwendung des gemeinsam genutzten Speichers ist hoch, daher wäre die Implementierung der Funktionalität sehr komplex. In Bezug auf die Nutzung in solchen Fällen nicht wert.
Was ist, wenn nicht alle Prozesse auf den gemeinsam genutzten Speicher zugreifen müssen, sondern nur sehr wenige Prozesse ihn benötigen? Es ist besser, ihn mit Nachrichtenwarteschlangen zu implementieren.
Wenn wir mit verschiedenen Datenpaketen kommunizieren möchten, sagen wir, dass Prozess A Nachrichtentyp 1 an Prozess B, Nachrichtentyp 10 an Prozess C und Nachrichtentyp 20 an Prozess D sendet. In diesem Fall ist die Implementierung mit Nachrichtenwarteschlangen einfacher. Um den angegebenen Nachrichtentyp als 1, 10, 20 zu vereinfachen, kann er entweder 0 oder + ve oder –ve sein, wie unten erläutert.
Natürlich ist die Reihenfolge der Nachrichtenwarteschlange FIFO (First In First Out). Die erste in die Warteschlange eingefügte Nachricht ist die erste, die abgerufen wird.
Die Verwendung von Shared Memory oder Message Queues hängt von den Anforderungen der Anwendung ab und davon, wie effektiv sie genutzt werden kann.
Die Kommunikation über Nachrichtenwarteschlangen kann auf folgende Arten erfolgen:
Schreiben in den gemeinsam genutzten Speicher durch einen Prozess und Lesen aus dem gemeinsam genutzten Speicher durch einen anderen Prozess. Wie wir wissen, kann das Lesen auch mit mehreren Prozessen erfolgen.
Schreiben in den gemeinsam genutzten Speicher durch einen Prozess mit unterschiedlichen Datenpaketen und Lesen aus diesem durch mehrere Prozesse, dh gemäß Nachrichtentyp.
Nachdem bestimmte Informationen zu Nachrichtenwarteschlangen angezeigt wurden, ist es jetzt an der Zeit, nach dem Systemaufruf (System V) zu suchen, der die Nachrichtenwarteschlangen unterstützt.
Um die Kommunikation über Nachrichtenwarteschlangen durchzuführen, gehen Sie wie folgt vor:
Step 1 - Erstellen Sie eine Nachrichtenwarteschlange oder stellen Sie eine Verbindung zu einer bereits vorhandenen Nachrichtenwarteschlange her (msgget ()).
Step 2 - In die Nachrichtenwarteschlange schreiben (msgsnd ())
Step 3 - Aus der Nachrichtenwarteschlange lesen (msgrcv ())
Step 4 - Führen Sie Steueroperationen für die Nachrichtenwarteschlange aus (msgctl ()).
Lassen Sie uns nun die Syntax und bestimmte Informationen zu den oben genannten Aufrufen überprüfen.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg)
Dieser Systemaufruf erstellt oder ordnet eine System V-Nachrichtenwarteschlange zu. Folgende Argumente müssen übergeben werden -
Das erste Argument, key, erkennt die Nachrichtenwarteschlange. Der Schlüssel kann entweder ein beliebiger Wert sein oder von der Bibliotheksfunktion ftok () abgeleitet werden.
Das zweite Argument, shmflg, gibt die erforderlichen Nachrichtenwarteschlangen-Flags an, z. B. IPC_CREAT (Erstellen einer Nachrichtenwarteschlange, falls nicht vorhanden) oder IPC_EXCL (Wird mit IPC_CREAT zum Erstellen der Nachrichtenwarteschlange verwendet und der Aufruf schlägt fehl, wenn die Nachrichtenwarteschlange bereits vorhanden ist). Müssen auch die Berechtigungen übergeben.
Note - Einzelheiten zu Berechtigungen finden Sie in früheren Abschnitten.
Dieser Aufruf würde bei Erfolg eine gültige Kennung für die Nachrichtenwarteschlange zurückgeben (die für weitere Aufrufe der Nachrichtenwarteschlange verwendet wird) und bei einem Fehler -1. Um die Fehlerursache zu ermitteln, überprüfen Sie die Funktion errno variable oder perror ().
Verschiedene Fehler in Bezug auf diesen Aufruf sind EACCESS (Berechtigung verweigert), EEXIST (Warteschlange existiert bereits, kann nicht erstellt werden), ENOENT (Warteschlange existiert nicht), ENOMEM (nicht genügend Speicher zum Erstellen der Warteschlange) usw.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
Dieser Systemaufruf sendet / hängt eine Nachricht an die Nachrichtenwarteschlange (System V) an. Folgende Argumente müssen übergeben werden -
Das erste Argument, msgid, erkennt die Nachrichtenwarteschlange, dh die Kennung der Nachrichtenwarteschlange. Der Bezeichnerwert wird nach dem Erfolg von msgget () empfangen.
Das zweite Argument, msgp, ist der Zeiger auf die Nachricht, die an den Anrufer gesendet wird und in der Struktur des folgenden Formulars definiert ist:
struct msgbuf {
long mtype;
char mtext[1];
};
Die Variable mtype wird für die Kommunikation mit verschiedenen Nachrichtentypen verwendet, die im Aufruf von msgrcv () ausführlich erläutert werden. Die Variable mtext ist ein Array oder eine andere Struktur, deren Größe durch msgsz (positiver Wert) angegeben wird. Wenn das Feld mtext nicht erwähnt wird, wird es als Nachricht mit der Größe Null betrachtet, was zulässig ist.
Das dritte Argument, msgsz, ist die Größe der Nachricht (die Nachricht sollte mit einem Nullzeichen enden).
Das vierte Argument, msgflg, gibt bestimmte Flags wie IPC_NOWAIT an (wird sofort zurückgegeben, wenn keine Nachricht in der Warteschlange gefunden wird, oder MSG_NOERROR (schneidet den Nachrichtentext ab, wenn mehr als msgsz Bytes vorhanden sind).
Dieser Aufruf würde bei Erfolg 0 und bei einem Fehler -1 zurückgeben. Um die Fehlerursache zu ermitteln, überprüfen Sie die Funktion errno variable oder 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)
Dieser Systemaufruf ruft die Nachricht aus der Nachrichtenwarteschlange (System V) ab. Folgende Argumente müssen übergeben werden -
Das erste Argument, msgid, erkennt die Nachrichtenwarteschlange, dh die Nachrichtenwarteschlangen-ID. Der Bezeichnerwert wird nach dem Erfolg von msgget () empfangen.
Das zweite Argument, msgp, ist der Zeiger der vom Aufrufer empfangenen Nachricht. Es ist in der Struktur des folgenden Formulars definiert:
struct msgbuf {
long mtype;
char mtext[1];
};
Die Variable mtype wird für die Kommunikation mit verschiedenen Nachrichtentypen verwendet. Die Variable mtext ist ein Array oder eine andere Struktur, deren Größe durch msgsz (positiver Wert) angegeben wird. Wenn das Feld mtext nicht erwähnt wird, wird es als Nachricht mit der Größe Null betrachtet, was zulässig ist.
Das dritte Argument, msgsz, ist die Größe der empfangenen Nachricht (Nachricht sollte mit einem Nullzeichen enden).
Das vierte Argument, msgtype, gibt den Nachrichtentyp an -
If msgtype is 0 - Liest die erste empfangene Nachricht in der Warteschlange
If msgtype is +ve - Liest die erste Nachricht in der Warteschlange vom Typ msgtype (wenn msgtype 10 ist, liest nur die erste Nachricht vom Typ 10, obwohl sich zu Beginn möglicherweise andere Typen in der Warteschlange befinden).
If msgtype is –ve - Liest die erste Nachricht des niedrigsten Typs, die kleiner oder gleich dem absoluten Wert des Nachrichtentyps ist (z. B. wenn msgtype -5 ist, liest sie die erste Nachricht vom Typ kleiner als 5, dh Nachrichtentyp von 1 bis 5).
Das fünfte Argument, msgflg, gibt bestimmte Flags wie IPC_NOWAIT an (wird sofort zurückgegeben, wenn keine Nachricht in der Warteschlange gefunden wird, oder MSG_NOERROR (schneidet den Nachrichtentext ab, wenn mehr als msgsz Bytes vorhanden sind).
Dieser Aufruf würde die Anzahl der tatsächlich im mtext-Array bei Erfolg empfangenen Bytes und -1 im Fehlerfall zurückgeben. Um die Fehlerursache zu ermitteln, überprüfen Sie die Funktion errno variable oder perror ().
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msgid, int cmd, struct msqid_ds *buf)
Dieser Systemaufruf führt Steueroperationen der Nachrichtenwarteschlange (System V) aus. Folgende Argumente müssen übergeben werden -
Das erste Argument, msgid, erkennt die Nachrichtenwarteschlange, dh die Nachrichtenwarteschlangen-ID. Der Bezeichnerwert wird nach dem Erfolg von msgget () empfangen.
Das zweite Argument, cmd, ist der Befehl zum Ausführen der erforderlichen Steueroperation für die Nachrichtenwarteschlange. Gültige Werte für cmd sind -
IPC_STAT- Kopiert Informationen zu den aktuellen Werten jedes Mitglieds der Struktur msqid_ds in die übergebene Struktur, auf die buf zeigt. Dieser Befehl erfordert eine Leseberechtigung für die Nachrichtenwarteschlange.
IPC_SET - Legt die Benutzer-ID, die Gruppen-ID des Eigentümers, die Berechtigungen usw. fest, auf die der Struktur-Puffer verweist.
IPC_RMID - Entfernt die Nachrichtenwarteschlange sofort.
IPC_INFO - Gibt Informationen zu den Grenzwerten und Parametern der Nachrichtenwarteschlange in der Struktur zurück, auf die buf zeigt, die vom Typ struct msginfo ist
MSG_INFO - Gibt eine msginfo-Struktur zurück, die Informationen zu den von der Nachrichtenwarteschlange verbrauchten Systemressourcen enthält.
Das dritte Argument, buf, ist ein Zeiger auf die Nachrichtenwarteschlangenstruktur mit dem Namen struct msqid_ds. Die Werte dieser Struktur würden entweder für set oder get gemäß cmd verwendet.
Dieser Aufruf würde den Wert abhängig vom übergebenen Befehl zurückgeben. Der Erfolg von IPC_INFO und MSG_INFO oder MSG_STAT gibt den Index oder die Kennung der Nachrichtenwarteschlange oder 0 für andere Vorgänge und -1 im Fehlerfall zurück. Um die Fehlerursache zu ermitteln, überprüfen Sie die Funktion errno variable oder perror ().
Nachdem Sie die grundlegenden Informationen und Systemaufrufe in Bezug auf Nachrichtenwarteschlangen gesehen haben, ist es jetzt an der Zeit, dies mit einem Programm zu überprüfen.
Lassen Sie uns die Beschreibung sehen, bevor wir uns das Programm ansehen -
Step 1 - Erstellen Sie zwei Prozesse, einen zum Senden in die Nachrichtenwarteschlange (msgq_send.c) und einen zum Abrufen aus der Nachrichtenwarteschlange (msgq_recv.c).
Step 2- Erstellen des Schlüssels mit der Funktion ftok (). Zu diesem Zweck wird zunächst die Datei msgq.txt erstellt, um einen eindeutigen Schlüssel zu erhalten.
Step 3 - Der Sendevorgang führt Folgendes aus.
Liest die vom Benutzer eingegebene Zeichenfolge
Entfernt die neue Zeile, falls vorhanden
Wird in die Nachrichtenwarteschlange gesendet
Wiederholt den Vorgang bis zum Ende der Eingabe (STRG + D)
Sobald das Ende der Eingabe empfangen wurde, wird die Nachricht "Ende" gesendet, um das Ende des Prozesses anzuzeigen
Step 4 - Führt im Empfangsprozess Folgendes aus.
- Liest die Nachricht aus der Warteschlange
- Zeigt die Ausgabe an
- Wenn die empfangene Nachricht "Ende" lautet, wird der Vorgang beendet und beendet
Zur Vereinfachung verwenden wir für dieses Beispiel nicht den Nachrichtentyp. Außerdem schreibt ein Prozess in die Warteschlange und ein anderer Prozess liest aus der Warteschlange. Dies kann nach Bedarf erweitert werden, dh idealerweise würde ein Prozess in die Warteschlange schreiben und mehrere Prozesse aus der Warteschlange lesen.
Lassen Sie uns nun den Prozess überprüfen (Nachricht wird in die Warteschlange gesendet) - Datei: 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;
}
Kompilierungs- und Ausführungsschritte
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.
Es folgt der Code aus dem Nachrichtenempfangsprozess (Abrufen der Nachricht aus der Warteschlange) - Datei: 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;
}
Kompilierungs- und Ausführungsschritte
message queue: ready to receive messages.
recvd: "this is line 1"
recvd: "this is line 2"
recvd: "end"
message queue: done receiving messages.