1.POSIX概述
前面已经学习了LINUX进程通信方式的进程和FIFO两种方式,但是POSIX是与之前两种不同的方式,主要区别呢,在于使用管道和FIFO的时候,在写入管道之前,应该有一个进程已经做好了读的准备,它呢是以无格式的字节流的方式进行通信的,如果有另外的进程进行干扰的话,很有可能会造成错误的信息交换,而POSIX消息队列则不会出现这种问题,POSIX消息内容主要有以下几个属性,一个是优先级,一个是消息内容的最大长度,最后一个则是消息内容了,以这种方式进行进程间的通信,我们相信,会有较高的稳定性。POSIX的优先级,主要是两种方式,如果是POSIX那么返回的就是最大优先级的消息,如果是SYstem V那么可以返回特定优先级的消息
2.POSIX的特性
POSIX的最大特性在于其内核持续性,是不是可以这样理解,只要不进行消息队列的删除操作,那么,在该消息队列中,就一定会一直存在,也就是说,我们不需要进行提前等待消息的写入,只要OS不进行重新自举,那么消息队列就一定会一直存在。
3.POSIX消息的创建
#include<mqueue.h>
mqd_t mq_open(const char* name,int flag,/*mode_t mode,struct mq_attr *attr */);
//打开或者创建一个消息队列,成功则返回一个消息队列描述符,失败,则返回-1
mqd_close(mqd_t mqd);//根据消息队列描述符,关闭指定的消息队列
mqd_unlink(const char* name);//成功返回0,失败返回-1
主要说几个参数:
name:表示的是消息的名称,我们可以这样认为,这是一个路径名称类似于"/tmp/123"等等
flag:表示打开的方式,可以有这样的O_CREAT O_WRONLY 或者O_RDONLY,创建,可写,可读权限
mode:则是可选参数 ,在flag中含有O_CREAT参数,并且消息队列不存在的时候,才需要提供该参数,如果不提供,则是默认权限
attr:也是一个可选参数,同上,在flag中含有O_CREAT,并且消息队列不存在http://write.blog.youkuaiyun.com/postedit/38843637的时候,才需要该参数,设定该消息队列的属性,如果不提供,则表示默认属性
mq_close:关闭一个消息队列,关闭之后该消息队列并不删除,一个进程结束,自动调用关闭打开的消息队列
mq_unlink:用于删除一个消息队列,消息队列创建之后只有通过调用该函数或者内核自举的时候,才会进行消息队列的删除,每个消息队列都有一个保存当前打开该消息队列的引用计数器
main.c文件如下“http://write.blog.youkuaiyun.com/postedit/38843637
#include<stdio.h>
#include<mqueue.h>
#include<errno.h>
int main()
{
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
int flag=O_CREAT|O_RDONLY;
mqd_t mqd=mq_open("/tmp.321",flag,FILE_MODE,NULL);
if(mqd==-1)
{
printf("对不起,消息队列创建失败%s",strerror(errno));
return;
}
printf("恭喜您,消息队列创建成功\n");
mq_close(mqd);
}
makefile
test:main.o
cc -o test main.o -lrt
main.o:main.c
cc -c main.c
这里需要注意的是,FILE_MODE允许用户读写,组成员只读,其他成员也是只读,这些权限位会被当前进程的文件模式创建掩码修正但是FILE_MODE也是有着限制的,不可能是0777,用户的权限可以是读写执行,但是组用户最高是只读可执行。
就是这样还是会出现permission denied,所需要做的就是(如果不出现,当然就不用管了阿)
sudo mkdir /dev/mqueue
mount -t mqueue none /dev/mqueeu
然后执行 ./test就可以了!这样,消息队列就创建成功了,但是,总是出现错误代码13 ,也就是说,permission denied出错,我们需要使用管理员权限才行...,今天就暂时,写到这里吧
接下来说说,mqueue属性的设置和获取把
#include<errno.h>
#include<mqueue.h>
#include<stdio.h>
int main()
{
int flag=O_CREAT|O_RDWR;
mqd_t mqd=mq_open("/temp.124",flag,0766,NULL);
if(mqd==-1)
{
printf("sorry create mq failed:%s\n",strerror(errno));
return;
}
printf("# mq create successfully\n");
// get the attribute of the mqueue
struct mq_attr myAttr;
mq_getattr(mqd,&myAttr);
printf("队列的最大长度是%d\n",myAttr.mq_maxmsg);
printf("单个消息的最大长度是%d\n",myAttr.mq_msgsize);
printf("当前队列中消息的个数%d\n",myAttr.mq_curmsgs);
printf("开始设置新的属性队列中长度是13,\n");
struct mq_attr newAttr;
newAttr.mq_maxmsg=13;
mq_close(mqd);
mq_open("temp.124",flag,0766,&newAttr);
/*
int result=mq_setattr(mqd,&newAttr,&myAttr);
if(result==-1)
{
printf("设置出错%s\n",strerror(errno));
}
*/
mq_getattr(mqd,&newAttr);
printf("新的长度是%d\n",newAttr.mq_maxmsg);
mq_close(mqd);
return;
}
不知为何mq_setattr总是出错,提示结果是Invalid Argument ,但是如果关闭一下,然后填入相应的属性的时候,mqueue的属性就能正常了,,,很是诡异,也可能是我才疏学浅吧...
消息队列的发送和接收:mg_send.c
#include<string.h>
#include<stdio.h>
#include<mqueue.h>
#include<errno.h>
/****************************************************
***************该函数主要是进行进程对消息队列的注册
*****************************************************/
int main()
{
int flag =O_CREAT|O_RDWR;
mqd_t mqd=mq_open("/temp.123",flag,0644,NULL);
if(mqd==-1)
{
printf("i am sorry create the mqueue error%s\n",strerror(errno));
return 0;
}
char *but="send test";
if(-1==mq_send(mqd,but,strlen(but),300))
{
printf("send failed %s\n",strerror(errno));
goto error_proc;
}
else{
printf("send sucessfully\n");
}
error_proc:
mq_close(mqd);
}
mq_receive.c文件如下:
#include<stdio.h>
#include<mqueue.h>
#include<errno.h>
#include<string.h>
int main()
{
int flag=O_CREAT|O_RDWR;
mqd_t mqd=mq_open("/temp.123",flag,0644,NULL);
if(mqd==-1)
{
printf("congratulations mqueue created successfully\n");
return -1;
}
// we got the maxsize of the sigle msg
struct mq_attr old_attr={0};
mq_getattr(mqd,&old_attr);
char* buf=malloc(old_attr.mq_msgsize);
int pri=0;
if(-1!=mq_receive(mqd,buf,old_attr.mq_msgsize,&pri))
{
printf("what we got is %s\n",buf);
}
else
{
printf("receive error :%s\n",strerror(errno));
}
free(buf);
mq_close(mqd);
}
这样就能成功了,PS:
开始的时候,我一直在使用堆栈变量,char buf[256],但是一直提示错误 msg too long ,所以变幻了方式,自动获取该消息队列的单个消息的对大长度,然后使用该长度即可