消息队列简介
进程通信信号量方式传送信息量有限,管道只能传送无格式字节流,无疑给程序开发带来不便,消息队列克服了这些缺点。消息队列就是一个消息链表,可以把消息看做一个记录,具有特定格式,进程可以向其中按照一定规则添加新消息;另一些进程可以从消息队列读走消息。消息队列只有在内核重新启动,或者人工删除才会消失。消息队列内核持续性需要消息队列在系统范围内拥有唯一个键值,所以,要获得一个消息队列的描述字,必须提供该消息队列的键值。键值可以自己指定,也可以用函数自动生成。
键值函数结构
#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
读写消息队列无法满足要求时不阻塞。- 以下两种情况将创建消息队列:
- 没有与键值对应的消息队列,并且
msgflg
有IPC_CREAT
参数。key
参数为IPC_PRIVATE
。
消息队列发送函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sysmsg.h>
int megsend(int msgid,struct msgbuf *msgp,int msgsz,int msgflg);
功能:
- 向消息队列发送一条消息
参数:
- msgqid
消息队列描述字。- msgp
存放消息结构的地址。- msgsz
消息数据的长度。- msgflag
发送标志有意义的发送标志为IPC_NOWAIT
,指明在消息队列没有足够空间容纳要发送的消息时,是否等待。- 消息格式
struct msgbuf { long type; //可理解为消息在队列中编号 char ext[0]; //消息数据的首地址 }
消息队列接收函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msgid,struct msgbuf*msgp,int msgsz,long msgtpy,int msgflg);
功能:
从消息队列中读取消息,并把消息存储在msgp
指向的msgbuf
结构中,在成功读取一条消息后,消息队列中这条消息将被删除。
参数:
- msgid
消息队列描述字- msgp
存放读取消息的消息结构的地址- msgsz
消息的长度- msgtpy
消息描述字(也就是消息锁在消息队列中的标号)- msgflg
与读取相关的参数,常用IPC_NOWAIT
,表示没有数据可读的时候,不等待
消息队列删除函数
#include<sys/type.h>
#include<sys/ipc.h>
#Include<sys/msg.h>
int msgctl(int msgid,int cmd,struct msgid_ds *buf);
参数:
- msgid:
消息队列标识符- cmd:
所要采取的命令IPC_RMID
删除消息队列- buf:
权限信息
消息队列用法举例
#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct msg_buf
{
int mtype;
char data[255];
};
int main()
{
key_t key; //消息队列键值
int msgid; //消息队列描述符
int ret;
struct msg_buf msgbuf; //消息队列结构
key=ftok("/tmp/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(); //消息编号为自身进程ID (只要大于0就可以)
strcpy(msgbuf.data,"this is a message");
ret=msgsnd(msgid,&msgbuf,sizeof(msgbuf.data),IPC_NOWAIT); //向消息队列发送 编号为自身ID 内容为 this is a message的消息
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);//接收消息队列中编号为自身进程ID的消息
if(ret==-1)
{
printf("recv message err\n");
return -1;
}
printf("recv msg =[%s]\n",msgbuf.data); //打印接受的消息
}
程序运行结果:
[root@localhost mesg]# ls
msg msg.c
[root@localhost mesg]# ./msg
key =[ffffffff]
recv msg =[this is a message]