消息队列

消息队列,是消息的链接表,存放在内核中。

一个消息队列由一个标识符(即队列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;
}

运行结果:

Hander 指定消息队列的优先级 消息队列key_消息队列


Hander 指定消息队列的优先级 消息队列key_文件名_02


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);

原因分析可以参考这个链接:栈溢出

Hander 指定消息队列的优先级 消息队列key_#include_03

此时的取长度应为取结构体中的第二个元素长度,即sizeof(readbuf.mtext)