1 概述
System V消息队列使用消息队列标识符标识。具有足够特权的任何进程都可以往一个给定队列放置一个消息 / 读出一个消息。
- 对于系统中的每个消息队列,内核维护一个定义在<sys/msg.h>头文件中的信息结构:
struct msqid_ds
{
struct ipc_term msg_perm; // read_write perms
struct msg *msg_first; // ptr to first message on queue
struct msg *msg_last; // ptr to last message on queue
msglen_t msg_cbytes; // current # bytes on queue
msgqnum_t msg_qnum; // current # of messages on queue
msglen_t msg_qbytes; // max # of bytes allowed on queue
pid_t msg_lspid; // pid of last msgsnd()
pid_t msg_lrpid; // pid of last msgrcv()
time_t msg_stime; // time of last msgsnd()
time_t msg_rtime; // time of last msgrcv()
time_t msg_ctime; // time of last msgctl() (that changed the above)
};
2 msgget函数
msgget函数用于创建一个新的消息队列或访问一个已存在的消息队列。
#include <sys/msg.h>
// 成功返回非负标识符,否则返回-1
int msgget(key_t key, int oflag);
3 msgsnd函数
使用msgget打开一个消息队列后,使用msgsnd往其上放置一个消息。
#include <sys/msg.h>
// 成功返回0,否则返回-1
int msgsnd(int msqid, const void *ptr, size_t length, int flag);
4 msgrcv函数
使用msgrcv函数从某个队列中读出一个消息。
#include <sys/msg.h>
// 成功返回读入缓冲区中数据的字节数,否则返回-1
ssize_t msgrcv(int msqid, void *ptr, size_t length, long type, int flag);
- ptr参数指定所接收消息的存放位置。
- length指定了由ptr指向的缓冲区中数据部分的大小。
5 msgctl函数
msgctl函数提供一个消息队列上的各种控制操作。
#include <sys/msg.h>
// 成功返回0,否则返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buff);
msgctl函数提供3个命令。
- IPC_RMID: 从系统中删除由msqid指定的消息队列。
- IPC_SET: 给所指定的消息队列设置其msqid_ds结构的以下4个成员:msg_perm.uid, msg_perm.gid, msg_perm.mode和msg_qbytes。
- IPC_STAT: (通过buff参数)给调用者返回与所指定消息队列对于的当前msqid_ds结构。
#include "unpipc.h"
int main(int argc, char const *argv[])
{
int msqid;
struct msqid_ds info;
struct msqbuf buf;
msqid = Msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT);
buf.mtype = 1;
buf.mtext[0] = 1;
Msgsnd(msqid, &buf, 1, 0);
Msgctl(msqid, IPC_STAT, &info);
printf("read-write: %03o, cbytes = %lu, qnum = %lu, qbytes = %lu\n",
info.msg_perm & 0777, (ulong_t) info.msg_cbytes,
(ulong_t) info.msg_qnum, (ulong_t) info.msg_qbytes);
system("ipcs -q");
Msgctl(msqid, IPC_RMID, NULL);
exit(0);
}
6 简单的程序
msgcreate程序:创建一个消息队列
#include "unpipc.h"
int main(int argc, char const *argv[])
{
int c, oflag, mqid;
oflag = SVMSG_MODE | IPC_CREAT;
while ( (c = Getopt(argc, argv, "e")) != -1) {
switch (c) {
case 'e':
oflag |= IPC_EXCL;
break;
}
}
if (optind != argc -1)
err_quit("usage: msgcreate [-e] <pathname>");
// ftok - convert a pathname and a project
// identifier to a System V IPC key
mqid = Msgget(Ftok(argv[optind], 0), oflag);
exit(0);
}
msgsnd程序:
#include "unpipc.h"
int main(int argc, char const *argv[])
{
int mqid;
size_t len;
long type;
struct msgbuf *ptr;
if (argc != 4)
err_quit("usage: msgsnd <pathname> <#bytes> <type>");
len = atoi(argv[2]);
type = atoi(argv[3]);
mqid = Msgget(Ftok(argv[1], 0), MSG_W);
// 把一个指定了长度和类型的消息放置到队列中
ptr = Calloc(sizeof(long) + len, sizeof(char)); // calloc把申请的内存全部初始化为0
ptr->mtype = type;
Msgsnd(mqid, ptr, len, 0);
exit(0);
}
msgrcv程序
#include "unpipc.h"
#define MAXMSG (8192 + sizeof(long))
int main(int argc, char const *argv[])
{
int c, flag, mqid;
long type;
ssize_t n;
struct msgbuf *buff;
type = flag = 0;
while ( (c = Getopt(argc, argv, "nt:")) != -1) {
switch (c) {
case 'n':
flag |=IPC_NOWAIT;
break;
case 't':
type = atol(optarg);
break;
}
}
if (optind != argc - 1)
err_quit("usage: msgrcv[-n] [-t type] <pathname>");
mqid = Msgget(Ftok(argv[optind], 0), MSG_R);
buff = Malloc(MAXMSG);
n = Msgrcv(mqid, buff, MAXMSG, type, flag);
printf("read %d bytes, type = %ld\n", n, buff->mtype);
exit(0);
}
msgrmid程序
- 删除一个消息队列,以IPC_RMID命令调用msgctl
#include "unpipc.h"
#define MAXMSG (8192 + sizeof(long))
int main(int argc, char const *argv[])
{
int mqid;
if (argc != 2)
err_quit("usage: msgrmid <pathname>");
mqid = Msgget(Ftok(argv[1], 0), 0);
Msgctl(mqid, IPC_RMID, NULL);
exit(0);
}