消息队列:
消息队列也叫报文队列,它就是一个消息的链表.可以把消息看作一个记录,具有特定的格式.进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息,消息队列是随内核持续的,
如下图:
要想学好消息队列,我们必须对以下的几个函数要有所了解,
一个消息队列应具有以下几个顺序:
创建打开消息队列msgget()。
读数据从队列msgrcv()。
写数据到队列msgsnd()。
控制消息队列msgctl()。
Msgget()
函数的作用:创建一个消息队列。
函数的头文件:#include<sys/types.h>、#include<sys/ipc.h>、#include<sys/msg.h>
函数的原型:int msgget(key_t kry, int msgflg);
函数的各参数:
Key:键值,IPC_PRIVATE 设定一个数字,也可以由ftok获得,下面具体介绍。
Msgflg:同open一样的权限。
IPC_CREAT:创建新的消息队列
IPC_EXCL: 与IPC_CREAT一同使用,表示如果要创建的消息队列已经存在,则返回错误。
IPC_NOWAIT:读写消息队列要求无法得到满足时,不阻塞
函数的返回值:
成功:与健值key相对应的消息队列描述字
出错:返回 -1.
在以下两种情况下,将创建一个新的消息队列:
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);
}
Msgsnd()
函数的作用:写数据到消息队列中。
函数的原型:int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
函数各参数的作用:
Msgsnd:向消息队列发送一个消息,发送的消息存储在msgp指向的msgbuf中。
Mspg: 表示指向的一个消息结构类型。
Struct msgbuf
{
Long msgtype;
Char mtext[1];
};
Msgsz:表示消息的大小。
Msgflg:
IPC_NOWAIT:标明在消息队列没有足够空间容纳要发送的消息时msgsnd是否等待。
0:一直等待直到能写进去消息为止。
函数的返回值:
成功:返回0.
出错:返回 -1.
Msgrcv()
函数的作用:读出消息队列的数据。
函数的原型:int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);
函数各参数的作用:
Msqid:向消息队列读出一个消息,读出的消息存储在msgp指向的msgbuf中。
Mspg: 表示指向的一个消息结构类型。
Struct msgbuf
{
Long msgtype;
Char mtext[1];
};
Msgsz:表示读出消息的大小
Msgtyp:表示读取的消息的类型。
Msgflg:标志位
IPC_NOWAIT:如果没有满足条件的消息,调用立即返回,此时,errno=ENOSG,IPC_EXCEPT与msgtyp>0配合使用,返回队列中第一个类型不为msgtyp的消息。
IPC_NOERROR:如果队列中满足条件的消息内容大于所请求的msgsz字节,则吧该消息截断,截断部分将丢失。
函数的返回值:
成功:返回读出消息的实际字节数,
失败:返回 -1.
函数的功能:
从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);
}
Msgctl()
函数的作用:控制消息队列,可以删除消息对列。
函数的原型:int msgctl(int msgid, int cmd, struct msgid_ds * buf);
函数各参数的作用:
Msgid:消息的ID
Cmd:IPC_STAT:读取队列的结构,存储在buf指定的地址中。
IPC_SET:设置对列的权限
IPC_RMID:删除msqid标识的消息队列
Buf:描述消息队列的msggid_ds结构类型变量。
函数的返回值:
成功:返回0.
出错:返回 -1.
目前主要有两种类型的消息队列:
POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用
系统V消息队列是随内核持续的,只有在内核重起或者人工删除时,该消息队列才会被删除。
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,必须提供该消息队列的键值。
Ftok(键值)
函数的作用:获得键值
函数的原型:key_t ftok(char *pathname, char proj);
函数的头文件:#include <sys/ipc.h>、#include<sys/types.h>.
函数各参数的作用:
Pathname:文件名。
Proj:项目名(不为0即可)。
函数的返回值:返回文件名所对应的键值
程序例子:
#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.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();
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);
}