关于消息队列的基本介绍,前面在学习system V的消息队列时已经有过了解,linux进程间通信:system V消息队列
mq_open
:创建或打开一个消息队列mq_send
:向消息队列写入一条消息mq_receive
:从消息队列中读取一条消息mq_close
:关闭进程打开的消息队列mq_unlink
:删除一个消息队列mq_setattr
:设置消息队列的一些额外属性mq_getattr
:获取消息队列的一些额外属性mq_notify
:异步通知创建或打开一个消息队列
a. 头文件
b. 函数使用:
mqd_t mq_open(const char *name, int oflag);
mqd_t mq_open(const char *name, int oflag, mode_t mode,struct mq_attr *attr);
c. 函数功能:创建一个新的POSIX消息队列或者打开一个已存在的消息队列。且消息队列是由name标识
d. 函数参数:
name
用来标识需要创建或者打开的ipc对象oflag
O_CREAT/O_RDONLY/O_WRONLY/O_RDWR/O_EXCL/O_NOBLOCKmode
位掩码,用来设置权限 8进制attr
设置消息队列的属性,若为NULL,使用默认属性,linux 3.5以后版本也可以通过/proc查看设置 struct mq_attr {
long mq_flags; /* Flags (ignored for mq_open()) */
long mq_maxmsg; /* Max. # of messages on queue */
long mq_msgsize; /* Max. message size (bytes) */
long mq_curmsgs; /* # of messages currently in queue
(ignored for mq_open()) */
};
e. 函数返回值
成功:返回消息队列对象的描述符
失败:返回-1,并设置errno
关闭一个消息队列
a. 头文件 :#include
b. 函数使用:int mq_close(mqd_t mqdes);
c. 函数功能:关闭一个描述符为mqdes的消息队列
d. 返回值:
成功:返回0
失败:返回-1
e. 注意:POSIX消息队列在进程终止或者执行execve()时会自动关闭
删除消息队列
a. 头文件: #include
b. 函数使用: int mq_unlink(const char *name);
c. 函数功能:删除通过name标识的消息队列;在所有进程使用完该队列之后销毁该队列;若打开该队列的所有进程都已关闭,则立即删除
d. 返回值:
成功:0
失败:-1
向消息队列中写入消息
a. 头文件: #include
b. 函数使用: int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);
c. 函数功能:将msg_ptr所指向的缓冲区中的消息内容添加到描述符mqdes所引用的消息队列中
d. 函数参数:
mqdes
:消息队列描述符msg_ptr
: 指向存放消息的缓冲区指针msg_len
: 消息的长度[10,8192]msg_prio
: 消息队列中按优先级排序,设置为0标识无需优先级;该参数为POSIX消息队列和system V消息队列的差异,即POSIX是通过优先级来区分消息,system V是通过消息类型来区分消息e. 返回值
成功:0
失败:-1
从消息队列中接收数据
a. 头文件: #include
b. 函数使用: ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
c. 函数功能:默认从mqdes引用的消息队列中删除一条优先级最高、存放时间最长的消息;并将删除的消息保存在msg_ptr;
这里如果接收时指定优先级,可以读取指定优先级的消息,并存放在msg_ptr
d. 函数参数:
mqdes
:消息队列描述符msg_ptr
: 指向存放消息的缓冲区指针msg_len
: 消息的长度[10,8192]msg_prio
: 消息队列中按优先级排序,设置为0标识无需优先级;e. 返回值
成功:消息接收的字节数
失败:-1
获取/设置消息队列的属性信息
a. 头文件 #include
b. 函数使用:
int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr, struct mq_attr *oldattr);
c. 函数功能:获取或者修改一个由mqdes标识的消息队列的属性信息
d. 函数参数:
mqdes
消息队列的唯一标识newattr
设置修改后的mq_attr结构体类型的属性信息oldattr
修改前的属性信息,如果当前参数为NULL,则默认设置从mq_getattr中获取到的属性信息关于消息队列的属性设置如下两种方式:
echo num > /proc/sys/fs/mqueue/queues_max
echo num > /proc/sys/fs/mqueue/msg_max
echo num > /proc/sys/fs/mqueue/msgsize_max
mq_setattr
仅能设置mq_flagsmq_open
仅设置 mq_maxmsg
和 mq_msgsize
最终创建的POSIX消息队列的实例存放在/dev/mqueue
路径下
mq_demo.c
#include
#include
#include
#include
#include
#include
int main()
{
mqd_t mq_id;
//创建一个消息队列
if ((mq_id = mq_open("/posix_msgqueue",O_RDWR | O_CREAT, 0666, NULL)) == -1) {
printf("mq_open failed \n");
_exit(-1);
}
struct mq_attr mq;
//获取消息队列的各个属性
if (mq_getattr(mq_id ,&mq) == -1 ){
_exit(-1);
}
printf("mq_flags %ld\n",mq.mq_flags); //mq_open默认将当前属性忽略,则一般为0
printf("mq_maxmsg %ld\n",mq.mq_maxmsg); //消息队列可以接收的最大消息容量为10个,当达到10个,则当前进程阻塞
printf("mq_msgsize %ld\n",mq.mq_msgsize); //每个消最大容量
printf("mq_curmsgs %ld\n",mq.mq_curmsgs);
int ret;
if ((ret = fork()) == -1) {
printf("fork failed \n");
_exit(-1);
}
//创建子进程用来接收消息队列的信息,且接收的优先级为NULL,即默认接收优先级最高且存放时间最长的消息
else if (ret == 0 ) {
char msg_buf[mq.mq_msgsize];
memset (msg_buf , 0 , mq.mq_msgsize);
while(1) {
if (mq_receive(mq_id,msg_buf,mq.mq_msgsize,NULL) == -1) {
printf("mq_receive failed \n");
_exit(-1);
}
printf("child process receive msg :%s \n",msg_buf);
sleep(1);
}
}
else {
while(1) {
//父进程用来发送消息队列的信息,并设置发送的消息优先级为1
//如果父进程发送多个优先级消息,子进程指定具体的一个优先级消息进行接收即可
if (mq_send(mq_id,"hello world",sizeof("hello world"),1) == -1) {
printf("mq_send failed\n");
_exit(-1);
}
printf("parent process :send msg to mqueue success\n");
sleep(1);
}
}
//关闭当前进程对消息队列 mq_id的引用
mq_close(mq_id);
sleep(5);
//引用计数为0时,删除当前进程创建的消息队列
if(mq_unlink("/posix_msgqueue") == -1) {
printf("mq_unlink failed\n");
_exit(-1);
}
return 0;
}
我们知道如下三个参数,POSIX消息队列默认的属性值为
mq_flags = 0
mq_maxmsg = 10
mq_msgsize = 8192
通过如下代码可以分别看到mq_open
和mq_setattr
对属性值的设置
#include
#include
#include
#include
#include
int main () {
mqd_t mq_id;
/*使用mq_open同时对三个参数更改*/
struct mq_attr addr;
addr.mq_flags = O_NONBLOCK;
addr.mq_maxmsg = 5;
addr.mq_msgsize = 4096;
//将需要设置对属性参数设置为addr
mq_id = mq_open("/notify",O_WRONLY | O_CREAT, 0666, &addr);
if (mq_id == -1) {
printf("mq_open failed\n");
_exit(-1);
}
if (mq_getattr(mq_id,&addr) == -1) {
printf("mq_getattr failed\n");
_exit(-1);
}
//打印最终对设置结果
printf("mq_open set mq_flags = %ld\n",addr.mq_flags);
printf("mq_open set mq_maxmsg = %ld\n", addr.mq_maxmsg);
printf("mq_open set mq_msgsize = %ld\n", addr.mq_msgsize);
/*同样对所有的属性参数,使用mq_setattr进行设置*/
struct mq_attr attr;
attr.mq_flags = O_NONBLOCK;
attr.mq_maxmsg = 8;
attr.mq_msgsize = 2048;
if(mq_setattr(mq_id,&attr,NULL) == -1) {
printf("mq_set attr failed \n");
_exit(-1);
}
if (mq_getattr(mq_id,&attr) == -1) {
printf("mq_getattr failed\n");
_exit(-1);
}
printf("mq_setattr set mq_flags = %ld\n",attr.mq_flags);
printf("mq_setattr set mq_maxmsg = %ld\n", attr.mq_maxmsg);
printf("mq_setattr set mq_msgsize = %ld\n", attr.mq_msgsize);
return 0;
}
输出结果如下:
mq_open set mq_flags = 0
mq_open set mq_maxmsg = 5
mq_open set mq_msgsize = 4096
mq_setattr set mq_flags = 2048
mq_setattr set mq_maxmsg = 5
mq_setattr set mq_msgsize = 4096
可见,mq_flags参数只有mq_setattr系统调用能够成功设置
mq_maxmsg和mq_msgsize对属性仅能由mq_opn系统调用设置成功