目录

1. Posix 消息队列简介

2. API接口

2.1 创建或打开消息队列

2.2 发送消息

2.3 接收消息

2.4 获取、设置消息队列属性

2.5 关闭消息队列

2.6 删除消息队列

2.7 注册消息通知

3. 示例

3.1 消息生产者

3.2 消息消费者

3.3 编译运行

4. 通过文件系统操作消息队列

5. 参考文档


1. Posix 消息队列简介

Posix 消息队列是基于文件描述符的,因此可以使用诸如select、poll和epoll等IO多路复用方式,这应该是最大的优点,此外,它还是一个优先级队列,优先级最高的消息会先出队列。从我的开发经验来看,实际项目中并不推荐使用系统提供的消息队列,主要原因是限制太多,比如说Posix 消息队列,系统范围内能够创建的消息队列个数是优先的,此外,消息的大小和消息队列的容量也受限,还有一点是仅支持优先级,不支持FIFO,这一点SystemV消息队列是支持的。虽然不怎么使用,但是还是需要学习一下它的基本用法,这样后续需要自己设计的时候可以参考下。

Posix mq可以使用mq_open来创建或者获取,该函数返回消息队列描述符mqd_t,每个消息队列都有一个名字,以斜杠'/'开头,长度不超过NAME_MAX,且后面不能再有斜杠。不同的进程可以通过同一个名字来操作同一个消息队列。消息通过mq_sendmq_receive来接收和发送,当不需要消息队列的时候,使用mq_close关闭它,关闭不代表删除,消息队列具有系统生存期,可以使用mq_unlink来删除它。对了,Posix mq还提供一个异步接收消息的特性,使用mq_notify函数,该接口向消息队列注册或注销一个通知,希望有消息的时候能够通知它,通知方式有两种,一种是通过信号,一种是通过一个线程。这里限制比较多,首先,消息队列只能注册一个通知,其次,通知是一次性的,通知完如果还想继续通知需要重新注册,还有一点是如果消息被其它进程通过mq_receive取到了,通知不会发生。我感觉这是一个非常鸡肋的功能,O(∩_∩)O哈哈~

下面介绍下相关的接口和使用例子

2. API接口

2.1 创建或打开消息队列

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>/**
* @brief 创建或获取消息队列
*
* @params name 消息队列关联的名字,斜杠开头,长度不超过NAME_MAX(e.g. 255)
* @params oflag 标志位,可以O_RDONLY| O_WRONLY| O_RDWR| O_CLOEXEC| O_CREAT| O_EXCL| O_NONBLOCK
* 这里如果指定了O_CREAT标志位,还要填写额外两个参数,mode和attr
*
* @params mode,参考open函数,通常填0即可
* @params attr,设置一些属性
*           struct mq_attr {
*               long mq_flags;       /* 不用填 */
*               long mq_maxmsg;      /* Max. # 消息队列中消息最大个数 */
*               long mq_msgsize;     /* Max. message size (bytes) 最大容量 */
*               long mq_curmsgs;     /* 不用填写 */
*           };
* @returns 成功返回描述符,失败返回-1
*/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);# 需要加上编译选项-lrt
* Link with -lrt.

2.2 发送消息

#include <mqueue.h>/**
* @brief 发送消息,如果队列满了并且没有设置NONBLOCK标志位会阻塞
*
* @params mqdes 消息队列描述符
* @params msg_ptr 要发送的消息buffer
* @params msg_len 消息大小
* @params msg_prio 消息优先级
*
* @returns 成功返回0,失败返回-1
**/int mq_send(mqd_t mqdes, const char *msg_ptr,size_t msg_len, unsigned int msg_prio);#include <time.h>
#include <mqueue.h>/**
* @brief 同上,多了一个时间参数,用于控制在队列满了的情况下,等待多长时间
*
* @params abs_timeout 时间
* @returns 成功返回0,失败返回-1
**/int mq_timedsend(mqd_t mqdes, const char *msg_ptr,size_t msg_len, unsigned int msg_prio,const struct timespec *abs_timeout);# 编辑要加上 -lrt选项
Link with -lrt.

2.3 接收消息

#include <mqueue.h>/**
* @brief 接收消息,无消息时默认阻塞,可以设置不阻塞标志位更改
*
* @params mqdes 消息队列描述符
* @params msg_ptr 消息缓存buffer
* @params msg_len 消息缓存大小,必须大于mq_msgsize,这个值可以通过mq_getattr接口获得
* @params msg_prio 如果设置了则返回消息的优先级* @returns 成功返回消息大小,失败返回-1
**/ssize_t mq_receive(mqd_t mqdes, char *msg_ptr,size_t msg_len, unsigned int *msg_prio);#include <time.h>
#include <mqueue.h>/**
* @brief 功能同上,只不过多了一个阻塞时间
**/ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr,size_t msg_len, unsigned int *msg_prio,const struct timespec *abs_timeout);

2.4 获取、设置消息队列属性

#include <mqueue.h>/**
* @brief 获取消息队列属性
*
* @params mqdes 消息队列描述符
* @params attr 属性bufferstruct mq_attr {long mq_flags;       /* Flags: 0 or O_NONBLOCK */long mq_maxmsg;      /* Max. 最大消息个数 */long mq_msgsize;     /* Max. 消息队列最大容量 */long mq_curmsgs;     /* 当前队列消息数 */};
* @returns 成功返回0,失败返回-1
**/int mq_getattr(mqd_t mqdes, struct mq_attr *attr);/**
* @brief 设置消息队列属性
*
* @params mqdes 消息队列描述符
* @params attr 属性buffer, 这里实际上只能设置attr里面的mq_flags标志位
* @returns 成功返回0,失败返回-1
**/int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr,struct mq_attr *oldattr);# 编译链接选项 -lrt
Link with -lrt.

2.5 关闭消息队列

#include <mqueue.h>/**
* @brief 关闭消息队列,并不实际删除消息队列
*
* @params mqdes 消息队列描述符
* @returns 成功返回0,失败返回-1
**/int mq_close(mqd_t mqdes);

2.6 删除消息队列

#include <mqueue.h>
/**
* @brief 将消息队列从系统中删除,实际的销毁要等到所有进程关闭消息队列描述符才发生
*
* @params name 消息队列名字
* @returns 成功返回0,失败返回-1
**/int mq_unlink(const char *name);

2.7 注册消息通知

#include <mqueue.h>/**
* @brief 注册或注销一个消息通知,当收到消息的时候根据指定的方式进行回调,可以是信号也可以执行一个线程。仅执行一次,需要反复通知则每次都要重新注册,最多允许一个进程注册。只有消息队列从空变为非空并且没有其它进程等待消息的时候,才触发通知。
*
* @params mqdes 消息队列名字
* @params sevp, 为空表示注销,非空指定回调方式,或是信号或者是线程
* @returns 成功返回0,失败返回-1
**/int mq_notify(mqd_t mqdes, const struct sigevent *sevp);

3. 示例

3.1 消息生产者

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>#define MQ_NAME "/mq_0"struct smessage{char name[128];char content[1024];
};int main(int argc, char** argv)
{int ret = 0;if (argc < 4){printf("Usage: ./mq_write name message prio\n");return 0;}mqd_t mq_fd;// 打开或创建消息队列,如果指定C_CREAT标志位则需要提供额外两个参数mq_fd = mq_open(MQ_NAME, O_RDWR|O_CREAT, 0, NULL);if (mq_fd == (mqd_t)-1){perror(__FUNCTION__);return -1;}struct smessage msg;memset(&msg, 0, sizeof(msg));strncpy(msg.name, argv[1], strlen(argv[1]));strncpy(msg.content, argv[2], strlen(argv[2]));unsigned int prio = (unsigned int)atoi(argv[3]);// 发送消息ret = mq_send(mq_fd, (const char *)&msg, sizeof(msg), prio);if (ret == -1){perror("mq_send error");return ret;}printf("mq_send succ\n");return 0;
}

3.2 消息消费者

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>// 消息队列名字
#define MQ_NAME "/mq_0"struct smessage{char name[128];char content[1024];
};int main()
{mqd_t mq_fd;// 打开或创建消息队列,如果指定O_CREAT,则需要填充额外两个参数mq_fd = mq_open(MQ_NAME, O_RDWR|O_CREAT, 0, NULL);if (mq_fd == (mqd_t)-1){perror(__FUNCTION__);return -1;}// 获取消息队列属性,读取消息的时候要用到struct mq_attr attr;if (mq_getattr(mq_fd, &attr) == -1){perror("mq_getattr");return -1;}printf("mq_msgsize:%ld\n", attr.mq_msgsize);// 分配消息缓存char *buffer = malloc(attr.mq_msgsize);if (buffer == NULL){printf("malloc error\n");return -1;}memset(buffer, 0, attr.mq_msgsize);struct smessage *msg;unsigned int prio = 0;// 读取消息if (mq_receive(mq_fd, buffer,attr.mq_msgsize, &prio) != -1){msg = (struct smessage*)buffer;printf("recv msg, name:%s, content:%s, prio:%lu\n", msg->name, msg->content, prio);}else{perror("mq_receive error");}// 释放bufferfree(buffer);// 关闭消息队列mq_close(mq_fd);return 0;
}

3.3 编译运行

# Makefile
default:gcc -o mq_read mq_read.c -lrtgcc -o mq_write mq_write.c -lrt
clean:rm -rf mq_read mq_write

生产三条优先级不同的消息,可以看到读取的时候是按照优先级来读取的。

4. 通过文件系统操作消息队列

 # mkdir /dev/mqueue# mount -t mqueue none /dev/mqueue

5. 参考文档

5.1. https://www.man7.org/linux/man-pages/man7/mq_overview.7.html

================================================================================================

Linux应用程序、内核、驱动、后台开发交流讨论群(745510310),感兴趣的同学可以加群讨论、交流、资料查找等,前进的道路上,你不是一个人奥^_^。...

Linux进程间通信四 Posix 消息队列简介与示例相关推荐

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

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

  2. linux进程间通信:POSIX 消息队列

    文章目录 基本介绍 相关编程接口 编程实例 消息队列通信实例 消息队列属性设置实例 基本介绍 关于消息队列的基本介绍,前面在学习system V的消息队列时已经有过了解,linux进程间通信:syst ...

  3. Linux进程间通信六 Posix 共享内存简介与示例

    1. 共享内存简介 共享内存主要用于不同进程之间相互通信,因为操作的是同一块地址,不需要内核和用户层之间数据拷贝,属于最快的进程间通信方式,不过,为了防止读写冲突,一般需要额外的同步手段.之前介绍了S ...

  4. Linux进程间通信二 System V 消息队列简介与示例

    1. SystemV消息队列简介 消息队列,顾名思义即是存放消息的队列,内核为每个SystemV 维护了一个msg_queue的结构体,里面记录了每个消息队列的信息. struct msg_queue ...

  5. Linux进程间通信(管道、消息队列、共享内存、信号、信号量)

    目录 Linux进程间通信概述 1.管道 无名管道(pipe) 有名管道(fifo) 2.消息队列(msg) 消息队列的通信原理 消息队列相关api 消息队列收发数据 键值生成 消息队列移除 3.共享 ...

  6. 【Linux】Linux进程间通信——共享内存/消息队列/守护进程

    文章目录 进程间通信--共享内存/守护进程 一, 共享内存 1. 共享内存概念 2. 共享内存使用 1. 共享内存使用步骤 2. 共享内存操作函数 3. 共享内存常用操作命令 4. 共享内存使用示例: ...

  7. Linux进程间通信三 System V 信号量简介与示例

    1. System V信号量简介 SystemV信号量主要用于解决生产者和消费者问题,一个信号量能够控制多个资源,说它是信号量集也不为过. 2. API接口介绍 2.1 创建或打开信号量集 #incl ...

  8. Linux IPC实践(7) --Posix消息队列

    1. 创建/获取一个消息队列 #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For m ...

  9. Linux IPC POSIX 消息队列

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

最新文章

  1. 剑指offer_第3题_从尾到头打印链表
  2. 全国高校大学生竞赛质量提升工作推进会
  3. 头条号为什么把作者抛弃了?
  4. 如何自己养卡,快速提升信用卡额度?
  5. pb 如何导出csv_如何计算指数温度?
  6. ASP.NET生成WORD文档服务器部署注意事项
  7. java游戏服务器面试_我做游戏开发这八年
  8. Oracle 协议适配器错误
  9. 韦德螺旋: 这真是一个螺旋吗?
  10. MyEclipse8.5默认工作区间修改
  11. 拿什么拯救你,程序新丁?
  12. KMP算法(C语言版)
  13. 浅读《构建之法:现代软件工程》有感
  14. Linux进阶之环境变量文件/etc/profile、/etc/bashrc、/etc/environment
  15. 华为服务器系统图标,华为云 服务器图标 visio
  16. linux下编译ffmpeg很多报错,linux下ffmpeg库 ARM交叉编译
  17. 关于 Sem Ver(semantic versioning)
  18. 基于闪电连接过程优化算法的函数寻优算法
  19. Cannot access memory at adress 0xbf9
  20. win7环境下visualsvn-server的搭建与使用(Eclipse)整合版

热门文章

  1. Cocos2d-x 3.x plist+png 做动画
  2. javaScript初学者易错点
  3. wpf Visibility 动画
  4. GDI+ 中发生一般性错误
  5. git 文件全部标红_git冲突解决,代码冲突、合并冲突。【IDEA版本】
  6. 【控制】影响系统响应的因素
  7. Ardino基础教程 16_一位数码管
  8. ubuntu 11.04下Android开发环境的搭建!
  9. BRCM5.02编译五: fatal error: uuid/uuid.h: No such file or directory compilation terminated
  10. ios 容错处理JKDataHelper和AvoidCrash