定义:
unix早期通信机制之一的信号能够传送的信号量有限,管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便。消息队列(也叫做报文队列)则克服了这些缺点。
发展:
消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式。进程可以向其中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息。
分类:
目前主要有两种类型的消息队列:
POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用。
持续性:
系统V消息队列是随着内核持续的,只有在内核重启或人工删除时,该消息队列才会被删除。
键值:
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,必须提供该消息队列的键值。
# include <sys/types.h>
# include <sys/ipc.h>
key_t ftok(char *pathname, char proj)
功能:返回文件名对应的键值。
pathname:文件名
proj:项目名(不为0即可)
打开/创建
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg.h>
int msgget(key_t key, int msgflg)
key:键值,由ftok获得。
msgflg:标志位:
IPC_CREAT:创建新的消息队列
IPC_EXCL:与IPC_CREAT一同使用,表示如果要创建的消息队列已经存在,则返回错误。
IPC_NOWAIT:读写消息队列要求无法得到满足时,不阻塞.
返回值:与键值key相对应的消息队列描述字。
在以下两种情况下,将创建一个新的消息队列:
1、如果没有与键值key相对应的消息队列,并且msgflg中包含了IPC_CREAT标志位。
2、key参数为IPC_PRIVATE。
下面是一个例子:
int open_queue(key_t keyval)
{
int qid;
if((qid = msgget(keyval, IPC_CREAT)) == -1)
return -1;
return qid;
}
发送消息:
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg.h>
int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, intmsgflg)
功能:向消息队列中发送一条消息。
参数:
msqid:已打开的消息队列描述字
msgp:存放消息的结构
msgsz:消息数据长度
msgflg:发送标志,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待。
消息格式:
struct msgbuf
{
long mtype://消息类型
char mtext[1];//消息数据首地址
};
接收消息:
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg.h>
int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, longmsgtyp, int msgflg)
功能:从msqid代表的消息队列中读取一个msgtyp类型的消息,并把消息存储在msgp指向的msgbuf结构中。在成功地读取一条消息以后,队列中的这条消息将被删除。
下面是一个例子:
int read_message(int qid, long type, struct mymsgbuf *qbuf)
{
int result, length;
length = sizeof(struct mymsgbuf) - sizeof(long);
if((result = msgrcv(qid, qbuf, length, type, 0)) == -1)
return -1;
return result;
}
下面是一个实例:msg.c
# include <sys/types.h>
# include <sys/msg.h>
# include <unistd.h>
struct msg_buf
{
int mtype;
char data[255];
};
int main(void)
{
key_t key;
int msgid;
int ret;
struct msg_buf msgbuf;
key = ftok("/home/regry/test/2", 'a');
printf("key = [%x]\n", key);
msgid = msgget(key, IPC_CREAT | 0666);
if(msgid == -1)
{
printf("create error\n");
return -1;
}
msgbuf.mtype = getpid();
strcpy(msgbuf.data, "test haha");
ret = msgsnd(msgid, &msgbuf, sizeof(msgbuf.data),IPC_NOWAIT);
if(ret == -1)
{
printf("send message err\n");
return -1;
}
memset(&msgbuf, 0, sizeof(msgbuf));
ret = msgrcv(msgid, &msgbuf, sizeof(msgbuf.data),getpid(), IPC_NOWAIT);
if(ret == -1)
{
printf("recv message err\n");
return -1;
}
printf("recv msg = [%s]\n", msgbuf.data);
return 0;
}
运行结果
[regry@campusnetwork test]$ ./msg
key = [ffffffff]
recv msg = [test haha]