消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
特点:
1. 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
2. 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
3. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的 类型读取。
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// 创建或打开消息队列:成功返回队列ID,失败返回-1
1 int msgget(key_t key, int flag);
// 添加消息:成功返回0,失败返回-1
2 int msgsnd(int msqid, const void *ptr, size_t size, int flag);
// 读取消息:成功返回消息数据的长度,失败返回-1
3 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
// 控制消息队列:成功返回0,失败返回-1
4 int msgctl(int msqid, int cmd, struct msqid_ds *buf);//一般来说第三个参数设置为NULL
在以下两种情况下,msgget
将创建一个新的消息队列:
- 如果没有与键值key相对应的消息队列,并且flag中包含了
IPC_CREAT
标志位。 - key参数为
IPC_PRIVATE
。
函数msgrcv
在读取消息队列时,type参数有下面几种情况:
type == 0
,返回队列中的第一个消息;type > 0
,返回队列中消息类型为 type 的第一个消息;type < 0
,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。
可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值。(其他的参数解释,请自行度娘)
ftok系统IPC键值的格式转换函数
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
#include <sys/types.h>
#include <sys/ipc.h>
//函数原型:
key_t ftok( const char * fname, int id )
/*fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录。
id是子序号。虽然是int类型,但是只使用8bits(1-255)。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
查询文件索引节点号的方法是: ls -i
*/
代码示例:
msgGet.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
int msgid;
key_t key;
struct msgbuf readBuf;
struct msgbuf writeBuf = {988,"I am get ,thank you for send message"};
if((key = ftok(".", 'z')) < 0)//获取key值
{
perror("ftok");
exit(0);
}
printf("Message Queue get key:%d\n",key);//打印key值
if((msgid =msgget(key,IPC_CREAT|0777)) == -1)//创建消息队列
{
perror("masget error");
exit(0);
}
printf("My msgid is:%d\n",msgid);//打印消息队列ID
msgrcv(msgid, &readBuf, sizeof(readBuf.mtext),888,0);
printf("MsgGet: receive msg.mtext is: %s\n", readBuf.mtext);
printf("MsgGet: receive msg.mtype is: %ld\n", readBuf.mtype);
putchar('\n');
msgsnd(msgid,&writeBuf,sizeof(writeBuf.mtext),0);
printf("send over\n");
msgctl(msgid,IPC_RMID,NULL);//移除消息队列
return 0;
}
msgSend.c
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
int msgid;
key_t key;
struct msgbuf writeBuf = {888,"this is message from send"};
//888 msgGet接受的消息类型
struct msgbuf readBuf;
if((key = ftok(".", 'z')) < 0)
{
perror("ftok");
exit(0);
}
printf("Message Queue send key:%d\n",key);
if((msgid =msgget(key,IPC_CREAT|0777)) == -1)
{
perror("masget error");
exit(0);
}
printf("My msgid is:%d\n",msgid);
msgsnd(msgid,&writeBuf,sizeof(writeBuf.mtext),0);
printf("send over\n");
putchar('\n');
msgrcv(msgid, &readBuf, sizeof(readBuf.mtext),988,0);
//988 msgSend接收的消息类型
printf("MsgSend: receive msg.mtext is: %s\n", readBuf.mtext);
printf("MsgSend: receive msg.mtype is: %ld\n", readBuf.mtype);
msgctl(msgid,IPC_RMID,NULL);//移除消息队列
return 0;
}