文章目录

  • 基本介绍
  • 相关编程接口
  • 编程实例
    • 消息队列通信实例
    • 消息队列属性设置实例

基本介绍

关于消息队列的基本介绍,前面在学习system V的消息队列时已经有过了解,linux进程间通信:system V消息队列

  1. 支持不同进程之间以消息(messages)的形式进行数据交换,消息能够拥有自己的标识,且内核使用链表方式进行消息管理。
  2. 进程之间的通信角色为:发送者和接受者
    发送者:
    a. 获取消息队列的ID(key或者msgid)
    b. 将数据放入一个带有标识的消息结构体,发送到消息队列
    接受者:
    a. 获取消息队列的ID
    b. 指定标识的消息从消息队列中读出,然后进一步后续处理
  3. 支持不同的进程标记不同的消息优先级(0,1,2…),并由内核态维护对应消息类型的链表。
  4. 内核态的0号消息类型维护了一个链表,用来保存按照时间顺序加入的消息

相关编程接口

  • mq_open :创建或打开一个消息队列
  • mq_send :向消息队列写入一条消息
  • mq_receive :从消息队列中读取一条消息
  • mq_close :关闭进程打开的消息队列
  • mq_unlink :删除一个消息队列
  • mq_setattr :设置消息队列的一些额外属性
  • mq_getattr :获取消息队列的一些额外属性
  • mq_notify :异步通知
  1. 创建或打开一个消息队列
    a. 头文件 <mqueue.h> <sys/stat.h> <fcntl.h>
    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_NOBLOCK
      标记使用什么样的方式打开ipc对象
    • mode 位掩码,用来设置权限 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

  2. 关闭一个消息队列
    a. 头文件 :#include <mqueue.h>
    b. 函数使用:int mq_close(mqd_t mqdes);
    c. 函数功能:关闭一个描述符为mqdes的消息队列
    d. 返回值:
    成功:返回0
    失败:返回-1
    e. 注意:POSIX消息队列在进程终止或者执行execve()时会自动关闭

  3. 删除消息队列
    a. 头文件: #include <mqueue.h>
    b. 函数使用: int mq_unlink(const char *name);
    c. 函数功能:删除通过name标识的消息队列;在所有进程使用完该队列之后销毁该队列;若打开该队列的所有进程都已关闭,则立即删除
    d. 返回值:
    成功:0
    失败:-1

  4. 向消息队列中写入消息
    a. 头文件: #include <mqueue.h>
    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

  5. 从消息队列中接收数据
    a. 头文件: #include <mqueue.h>
    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

  6. 获取/设置消息队列的属性信息
    a. 头文件 #include <mqueue.h>
    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中获取到的属性信息

    关于消息队列的属性设置如下两种方式:

    • 通过proc文件系统
      echo num > /proc/sys/fs/mqueue/queues_max
      echo num > /proc/sys/fs/mqueue/msg_max
      echo num > /proc/sys/fs/mqueue/msgsize_max
    • 通过POSIX系统调用接口设置
      mq_setattr 仅能设置mq_flags
      mq_open 仅设置 mq_maxmsgmq_msgsize

编程实例

最终创建的POSIX消息队列的实例存放在/dev/mqueue路径下

消息队列通信实例

mq_demo.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>#include <mqueue.h>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默认将当前属性忽略,则一般为0printf("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_openmq_setattr对属性值的设置

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mqueue.h>
#include <string.h>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;//将需要设置对属性参数设置为addrmq_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系统调用设置成功

linux进程间通信:POSIX 消息队列相关推荐

  1. c语言系统编程八:Linux进程间通信之消息队列

    Linux进程间通信之消息队列 一 消息队列概述 二 消息队列的特点 三 消息队列的创建和使用 3.1 获取系统唯一的key值 3.2 创建消息队列 3.3 查看消息队列和删除消息队列的shell命令 ...

  2. Linux进程间通信——使用消息队列

    下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信--使用命名管道 一.什么是消息队列 消息队列提供了 ...

  3. Linux IPC POSIX 消息队列

    模型: #include<mqueue.h> #include <sys/stat.h> #include <fcntl.h> mq_open() //创建/获取消 ...

  4. linux 进程uhxuhao,linux 进程间通信三 消息队列以及实例

    转自 http://blog.csdn.net/liang890319/article/details/8280934 代码来自:嵌入式Linux应用开发标准教程 消息可以理解为写信给某个人,这里在应 ...

  5. Linux进程间通信(IPC)-------消息队列

    消息队列是进程间通信的一种方法,他有两个操作,一个进程来发送消息(也就是向内存中写入数据),另一个是获取消息(也就是另外一个进程在内存中读取数据) 下面来看消息队列的 创建,写入,读取等需要用到的函数 ...

  6. linux进程间通信:消息队列实现双端通信

    双端通信描述 利用消息队列针对发送接受消息的类型唯一性 进行多个客户端之间消息传递,而不需要server端进行消息转发. 同时消息队列的读阻塞和写阻塞特性(消息队列中已经写入数据,如果再不读出来,则无 ...

  7. linux进程间通信:POSIX 消息队列 ----异步通信

    在上一篇中linux进程间通信:POSIX 消息队列我们知道消息队列中在消息个数达到了队列所能承载的上限,就会发生消息的写阻塞. 阻塞式的通信影响系统效率,进程之间在通信收到阻塞时并不能去做其他事情, ...

  8. Linux进程间通信四 Posix 消息队列简介与示例

    目录 1. Posix 消息队列简介 2. API接口 2.1 创建或打开消息队列 2.2 发送消息 2.3 接收消息 2.4 获取.设置消息队列属性 2.5 关闭消息队列 2.6 删除消息队列 2. ...

  9. linux 消息对lie_Linux进程间通信之消息队列总结

    一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构(消息队列.信号量或共享存储段)都用一个非负整数的标识符( i d ...

最新文章

  1. 关于ADAM中自定义Class Schema后不能创建该Class的实例的问题
  2. python多元线性回归模型案例_Python 实战多元线性回归模型,附带原理+代码
  3. cookie,sessionStorage和localStorage的区别
  4. Rhythmk 一步一步学 JAVA(2) : 操作 MYSQL 数据库
  5. Linux Cpu 利用率计算
  6. 数据太大导致oracle数据库连接关闭,ORACLE异常关闭后导致数据库报错无法连接问题解决办法-Oracle...
  7. 漫谈SCA(软件成分分析)测试技术:原理、工具与准确性
  8. 【kafka】Kafka 源码解析:Group 协调管理机制
  9. Spring Boot中@Autowired可以省略的情况
  10. java 1.8 64_JDK 1.8 64位 下载 安装 配置
  11. almalinux8 编译openssh 9.1p1生成rpm包并验证安装
  12. 高低温试验箱的11点使用注意事项说明
  13. GC算法精解(五分钟让你彻底明白标记/清除算法)
  14. Window下,C++ 操作 Mysql、Url、utf-8文件 编码问题(读取和写入)
  15. UVa 220 黑白棋 算法竞赛入门经典 习题4-3
  16. 利用Android9.0虚拟机的JVMTI技术实现一些黑科技
  17. 河南省第四届”金盾信安杯”网络安全大赛writeup(过程,解题思路)
  18. go库函数之-time-使用示例
  19. svn服务器web项目,liunx 搭建svn服务器并实现钩子自动更新到web项目
  20. 通过RViz中的InteractiveMarkers在ROS中仿真力和力矩(wrench.force和wrench.torque)

热门文章

  1. 薏米红豆粥的功效和实践演示
  2. hdu2236 无题II 最大匹配 + 二分搜索
  3. msvcrt.lib和LIBCD.lib链接冲突
  4. xdoj 1144 K叉哈弗曼树
  5. usaco wormhole(看了官方视频题解)
  6. 微信小程序 python接口_微信小程序-封装请求基准路径、接口API 和使用
  7. bd2和mysql语法区别,经验:在MySQL数据库中,这4种方式可以避免重复的插入数据!...
  8. 油品调和计算软件_燕山石化汽油在线调和系统完成升级改造
  9. 24核服务器配什么系统,24核服务器
  10. jquery 图片裁剪 java_[Java教程]5 款最新的 jQuery 图片裁剪插件