必须先通过 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"); ...