2.9 Message Queues (msgget, msgctl, msgsnd, msgrcv)


Nachrichten (Messages) ermöglichen es einem Prozess, formatierte Daten an einen anderen Prozess zu übertragen. Dazu muss zuerst eine Message Queue (Warteschlange für Nachrichten) eingerichtet werden. Ein Prozess kann Nachrichten an eine bestimmte (oder mehrere) Message Queues schicken, und andere Prozesse können diese Nachrichten von dort empfangen.

Folgende Schritte sind notwendig, einem Prozess die Nutzung einer Message Queue zu ermöglichen:

  1. Warteschlange erzeugen bzw. öffnen msgget()
    Die Warteschlange muss zuerst erzeugt oder geöffnet werden, falls diese bereits existiert.
  2. Nachrichten in die Warteschlange schreiben msgsnd()
  3. Nachrichten aus der Warteschlange lesen msgrcv()
  4. Verwalten und steuern einer Warteschlange msgctl()

FIFO

 

int msgget(key_t key, int msgflg)
Mit der Funktion msgget() wird eine Message Queue vom Betriebssystem angefordert und ggf. angelegt.

  • Der Parameter key ist der Schlüssel (Name) der Message Queue im System (der Typ key_t ist als long definiert).
  • Der Parameter msgflag setzt die Zugriffsrechte der Message Queue. Normalerweise wird hier IPC_CREAT angegeben, um eine neue Message Queue anzulegen. Wenn IPC_CREAT nicht gesetzt ist, dann wird die ID der existierenden Message Queue zurückgeliefert, soferne diese existiert. Zusätzlich kann noch IPC_EXCL hinzugefügt werden, um mit einer Fehlermeldung die Programmausführung zu beenden, falls eine Message Queue mit dem angegebenen Key bereits existiert. Falls man eine neue Message Queue erzeugen möchte, so sollten bei Flags (IPC_CREAT und IPC_EXCL) gesetzt werden. 
Bei korrektem Ablauf gibt die Funktion als Returnwert eine nicht negative ID der Message Queue zurück. Im Fehlerfall ist der Returnwert -1 und die Variable errno wird gesetzt.

int msgsnd(int msgid, struct msgbuf *msgp, int msgsz, int msgflag)
Mit der Funktion msgsnd() wird eine Nachricht in die Message Queue geschrieben. Die Angabe des Typs der Nachricht wird innerhalb der Struktur msgbuf eingefügt:

  • Der Parameter msgid ist die ID der Message Queue (vom Befehl msgget() zurückgeliefert).
  • Der Parameter msgp ist ein Zeiger auf eine Struktur der Nachricht. Z. B.       

struct msgbuf {
   long mtype;                     // message type
   char mtext[SOMEVALUE];
}

         Durch den Wert für mtype kann man Nachrichten klassifizieren. Der Empfänger kann über diesen Wert kontrollieren,              von welchen Sender oder welchen Nachrichtentyp er empfangen möchte.

  • Der Parameter msgsz gibt die Größe der Nachricht (ohne mtype; siehe unten).
  • Der Parameter msgflag bestimmt die Art des Zugriffs auf die Queue; bei IPC_NOWAIT wartet die Funktion msgsnd() nicht, wenn die Message Queue voll ist, sondern beendet sich mit dem Returnwert -1. In diesem Fall muss die Nachricht erneut gesendet werden.  Wenn IPC_NOWAIT nicht gesetzt ist, dann wird der aufrufende Prozess solange blockiert (falls nicht ausreichende Systemressourcen zur Verfügung stehen), bis die Nachricht erfolgreich übertragen werden kann. 

Der Returnwert der Funktion ist bei korrektem Ablauf 0. Im Fehlerfall gibt die Funktion den Wert -1 zurück und setzt die Systemvariable errno.

int msgrcv(int msgid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflag)
Mit der Funktion msgrcv() wird eine Nachricht aus der Message Queue ausgelesen.

  • Der Parameter msgid ist die ID der Message Queue (vom Befehl msgget()).
  • Der Parameter msgp ist ein Zeiger auf eine Struktur der Nachricht (siehe msgsnd()).
  • Der Parameter msgsz ist die Größe der Nachricht, die maximal gelesen werden darf (ohne mtype; siehe msgsnd()).
  • Der Parameter msgtyp ist der Typ der Nachricht, die ausgelesen werden soll.
    • msgtyp == 0: die erste Nachricht die in die Message Queue geschickt worden ist, wird gelesen.
    • msgtyp > 0: die Nachricht  mit dem diesem msgtyp Wert wird empfangen.
    • msgtyp < 0: die Nachricht mit kleinstem msgtyp Wert die kleiner als der Absolutbetrag von msgtyp (in msgrcv) wird zuerst empfangen. Wenn es 3 Nachrichten mit msgtyp 999, 5 und 1 gibt und msgtyp = -999, und msgrcv wird 3mal aufgerufen, dann werden die Nachrichten in der Reihenfolge 1, 5 und 999 empfangen.
  • Der Parameter msgflag bestimmt die Art des Zugriffs auf die Queue; bei IPC_NOWAIT wartet die Funktion msgrcv() nicht, bis in der Message Queue eine Nachricht ist, sondern beendet sich mit dem Returnwert -1. Wenn IPC_NOWAIT nicht gesetzt ist, dann wartet der Prozess solange bis eine Nachricht with passenden Parameterwerten ankommt. Wenn MSG_NOERROR gesetzt ist, dann wird ein zu lange Nachricht einfach abgeschnitten, wenn diese länger ist als durch msgsz vorgegeben. 

Der Returnwert der Funktion ist bei korrektem Ablauf 0. Im Fehlerfall gibt die Funktion den Wert -1 zurück und setzt die Variable errno.

int msgctl(int msgid, int cmd, struct msgid_ds *buf)
Die Funktion msgctl() dient zur Steuerung einer Message Queue.

  • Der Parameter msgid ist die ID der Message Queue (vom Befehl msgget()).
  • Der Parameter cmd ist das Steuerkommando; folgende Kommandos sind möglich:
    • IPC_STAT: Es kann der aktuelle Status der Message Queue abgefragt werden. Das Ergebnis wird in buf geschrieben.
    • IPC_SET: Die Zugriffsrechte können geändert werden.
    • IPC_RMID: Die Message Queue wird gelöscht.
  • Der Parameter buf ist eine Struktur vom Typ struct msgid_ds und wird für das Kommando IPC_STAT benötigt.

Der Returnwert der Funktion ist bei korrektem Ablauf 0. Im Fehlerfall gibt die Funktion den Wert -1 zurück und setzt die Variable errno.

Beispiel
#include<stdio.h>
#include<string.h>
#include<time.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/wait.h>
#include<sys/errno.h>

extern int errno;
#define MSGPERM 0600
int msgqid, rc;
int done;
time_t _ltime;
struct q_type {
long mtype;
char mtext[81];
}q_entry;

int main(int argc,char **argv)
{
int statloc;
msgqid=msgget(IPC_PRIVATE,MSGPERM|IPC_CREAT|IPC_EXCL);
/* create message queue, abort if message queue with the same key exists */
if (msgqid < 0) {
perror( strerror(errno) );
printf("msgget failed, msgqid = %d\n", msgqid);
exit(1);
}

printf("message queue %d created\n",msgqid);
q_entry.mtype=1; /* set the type of message */
_ltime = time(&_ltime); /* retrieving current time by calling time() */
sprintf (q_entry.mtext,"%s\n",ctime(&_ltime)); /* setting the right time format by means of ctime() */
rc = msgsnd(msgqid,&q_entry,80,0);
/* take IPC_NOWAIT instead of 0, if you want the process not to suspend,
if message delivery is not possible at the moment */
if (rc < 0) {
perror( strerror(errno) );
printf("msgsnd failed, rc = %d\n", rc);
exit(1);
}
rc=msgrcv(msgqid,&q_entry,80,0,0);
if (rc < 0) {
perror( strerror(errno) );
printf("msgrcv failed, rc=%d\n", rc);
exit(1);
}
printf("received msg: %s\n", q_entry.mtext);

rc=msgctl(msgqid,IPC_RMID,NULL);
if (rc < 0) {
perror( strerror(errno) );
printf("msgctl (return queue) failed, rc=%d\n", rc);
exit(1);
}
printf("message queue %d is gone\n",msgqid);
}
Das Programm msg.c downloaden...