Before a process can send or receive a message, the queue must be initialized through the msgget(2) function. The owner or creator of a queue can change its ownership or permissions using msgctl(2). Also, any process with permission to do so can use msgctl(2) for control operations.
IPC messaging lets processes send and receive messages, and queue messages for processing in an arbitrary order. Unlike the file byte-stream data flow of pipes, each IPC message has an explicit length.
Messages can be assigned a specific type. Because of this, a server process can direct message traffic between clients on its queue by using the client process PID as the message type. For single-message transactions, multiple server processes can work in parallel on transactions sent to a shared message queue.
Operations to send and receive messages are performed by the msgsnd(2) and msgrcv(2) functions, respectively. When a message is sent, its text is copied to the message queue. The msgsnd(2) and msgrcv(2) functions can be performed as either blocking or non-blocking operations. A blocked message operation remains suspended until one of the following three conditions occurs:
The call succeeds.
The process receives a signal.
The queue is removed.
The msgget(2) function initializes a new message queue. It can also return the message queue ID (msqid) of the queue corresponding to the key argument. The value passed as the msgflg argument must be an octal integer with settings for the queue's permissions and control flags.
The MSGMNI kernel configuration option determines the maximum number of unique message queues that the kernel will support. msgget() fails when this limit is exceeded. The following code illustrates the msgget() function.
#include <sys/ipc.h> #include <sys/msg.h> ... key_t key; /* key to be passed to msgget() */ int msgflg, /* msgflg to be passed to msgget() */ msqid; /* return value from msgget() */ ... key = ... msgflg = ... if ((msqid = msgget(key, msgflg)) == -1) { perror("msgget: msgget failed"); exit(1); } else (void) fprintf(stderr, "msgget succeeded"); ...
The msgctl(2) function alters the permissions and other characteristics of a message queue. The msqid argument must be the ID of an existing message queue. The cmd argument is one of:
The following code illustrates the msgctl(2) function with all its various flags:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ... if (msgctl(msqid, IPC_STAT, &buf) == -1) { perror("msgctl: msgctl failed"); exit(1); } ... if (msgctl(msqid, IPC_SET, &buf) == -1) { perror("msgctl: msgctl failed"); exit(1); } ...
The msgsnd(2) and msgrcv(2) functions send and receive messages, respectively. The msqid argument must be the ID of an existing message queue. The msgp argument is a pointer to a structure that contains the type of the message and its text. The msgsz argument specifies the length of the message in bytes. Various control flags can be passed in the msgflg argument.
The following code illustrates msgsnd(2) and msgrcv(2):
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ... int msgflg; /* message flags for the operation */ struct msgbuf *msgp; /* pointer to the message buffer */ size_t msgsz; /* message size */ size_t maxmsgsize; long msgtyp; /* desired message type */ int msqid /* message queue ID to be used */ ... msgp = malloc(sizeof(struct msgbuf) - sizeof (msgp->mtext) + maxmsgsz); if (msgp == NULL) { (void) fprintf(stderr, "msgop: %s %ld byte messages.\n", "could not allocate message buffer for", maxmsgsz); exit(1); ... msgsz = ... msgflg = ... if (msgsnd(msqid, msgp, msgsz, msgflg) == -1) perror("msgop: msgsnd failed"); ... msgsz = ... msgtyp = first_on_queue; msgflg = ... if (rtrn = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg) == -1) perror("msgop: msgrcv failed"); ...