消息队列
消息队列,是消息的链接表,存放在内核中。
一个消息队列由一个标识符(即队列ID)来标识。
1、特点
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
2、原型
2.1//获取key
key_t ftok( const char * fname, int id )
fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录。
id是子序号可以为数字或者字符。
2.2创建或打开消息队列:成功返回队列ID,失败返回-1
int msgget( key, int msgflag);
在以下两种情况下,msgget将创建一个新的消息队列:
- 如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志位。
- key参数为IPC_PRIVATE。
2.3添加消息:成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t size, int flag);
mspid: 通过mspid = msgget();获取
const void *ptr:ptr为一个数组,形式如下
struct msgbuf {
long mtype;
char mtext[1]
};
size_t size:切记!!!这里用的是msgbuf.mtext的大小
flag:一般写0
2.4读取消息:成功返回消息数据的长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
mspid: 通过mspid = msgget();获取
const void *ptr:ptr为一个数组,形式如下
struct msgbuf {
long mtype;
char mtext[1]
};
size_t size:切记!!!这里用的是msgbuf.mtext的大小,不然会导致栈溢出。后面会详细说明
long type:自己定义的
flag:一般写0
2.5 控制消息队列:成功返回0,失败返回-1(常用释放队列)
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int cmd:一般用IPC_RMID 来清除队列
struct msqid_ds *buf:一般用NULL
3.例子
msg_Get.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include <sys/ipc.h>
struct msgBuf{
long mtype;
char mtext[256];
};
int main()
{
struct msgBuf readbuf;
struct msgBuf writebuf = {808,"This is msg from msgGet!"};
// 1.Get Key
key_t key;
key = ftok(".",'z');
if(key < 0){
printf("Get Key Error!\n");
}
else{
printf("Get Key Success!\n");
}
//2.Creat
int msgId = msgget(key,IPC_CREAT|0777);
if (msgId == -1)
{
printf("msgGet Creat Failed!\n");
}
else{
printf("msgGet Creat Success!\n");
}
//3.Receive
msgrcv(msgId,&readbuf,sizeof(readbuf.mtext),818,0);
printf("Msg From msgSent:%s\n",readbuf.mtext);
//4.Sent
msgsnd(msgId,&writebuf,sizeof(writebuf.mtext),0);
//5.Free msdId
msgctl(msgId,IPC_RMID,NULL);
return 0;
}
msg_Sent.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include <sys/ipc.h>
struct msgBuf{
long mtype;
char mtext[256];
};
int main()
{
struct msgBuf writebuf = {818,"This is msg from msgSent!"};
struct msgBuf readbuf;
// 1.Get Key
key_t key;
key = ftok(".",'z');
if(key < 0){
printf("Get Key Error!\n");
}
else{
printf("Get Key Success!\n");
}
//2.Creat
int msgId = msgget(key,IPC_CREAT|0777);
if (msgId == -1)
{
printf("msgSent Creat Failed!\n");
}
else{
printf("msgSent Creat Success!\n");
}
//3.Send
msgsnd(msgId,&writebuf,sizeof(writebuf.mtext),0);
//4.Receive
msgrcv(msgId,&readbuf,sizeof(readbuf.mtext),808,0);
printf("Msg From msgGet:%s\n",readbuf.mtext);
//5.Free msdId
msgctl(msgId,IPC_RMID,NULL);
return 0;
}
运行结果:
4.遇到的问题
在两个代码中的Send部分和Reserve部分中间的取长度都写的为取整个结构体的长度,结果在执行后报错,如下
*** stack smashing detected ***: ./a.out terminated
原代码:
//3.Receive
msgrcv(msgId,&readbuf,sizeof(readbuf),818,0);
printf(“Msg From msgSent:%s\n”,readbuf.mtext);
//4.Sent
msgsnd(msgId,&writebuf,sizeof(readbuf),0);
原因分析可以参考这个链接:栈溢出
此时的取长度应为取结构体中的第二个元素长度,即sizeof(readbuf.mtext)