必须先通过 msgget(2) 初始化队列,然后进程才能发送或接收消息。 队列的属主或创建者可以使用 msgctl(2) 更改队列的拥有权或权限。 任何具有相应权限的进程均可使用 msgctl(2) 执行控制操作。
通过 IPC 消息传送,进程可以发送和接收消息以及对消息进行排队,以便按任意顺序处理。 与管道的文件字节流数据流不同,每条 IPC 消息都具有显式长度。
可以为消息指定特定类型。 因此通过使用客户机进程 PID 作为消息类型,服务器进程可以将客户机的消息流量分散到其队列中。 对于单消息事务,多个服务器进程可以并行处理发送到共享消息队列的事务。
发送和接收消息的操作分别通过 msgsnd(2) 和 msgrcv(2) 执行。 发送消息时,会将消息的文本复制到消息队列。msgsnd(2) 和 msgrcv(2) 可以作为阻塞操作和非阻塞操作执行。 被阻塞的消息操作将保持暂停状态,直到出现以下三种情况之一:
调用成功。
进程接收到信号。
队列被删除。
msgget(2) 可初始化新的消息队列, 并且还可返回对应于密钥参数的队列的消息队列 ID (msqid)。 作为 msgflg 参数传递的值必须为八进制整数,并具有该队列的权限和控制标志的设置。
MSGMNI 内核配置选项确定内核支持的单一消息队列数的最大个数。如果超过此限制,msgget(2) 会失败。
以下代码说明了 msgget(2)。
#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");
...
msgctl(2) 可更改消息队列的权限和其他特性。 msqid 参数必须为现有消息队列的 ID。 cmd 参数为以下各项之一:
以下代码说明了 msgctl(2) 及其各种标志。
#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);
}
...
msgsnd(2) 和 msgrcv(2) 分别发送和接收消息。 msqid 参数必须为现有消息队列的 ID。 msgp 参数是指向包含消息类型及其文本的结构的指针。 msgsz 参数以字节为单位指定消息的长度。 msgflg 参数传递各种控制标志。
以下代码说明了 msgsnd(2) 和 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");
...