首页 > linux进程间通信:POSIX 消息队列

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

文章目录

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

基本介绍

关于消息队列的基本介绍,前面在学习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. 头文件

    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

    b. 函数使用:int mq_close(mqd_t mqdes);

    c. 函数功能:关闭一个描述符为mqdes的消息队列

    d. 返回值:

    成功:返回0

    失败:返回-1

    e. 注意:POSIX消息队列在进程终止或者执行execve()时会自动关闭

  3. 删除消息队列

    a. 头文件: #include

    b. 函数使用: int mq_unlink(const char *name);

    c. 函数功能:删除通过name标识的消息队列;在所有进程使用完该队列之后销毁该队列;若打开该队列的所有进程都已关闭,则立即删除

    d. 返回值:

    成功:0

    失败:-1

  4. 向消息队列中写入消息

    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

  5. 从消息队列中接收数据

    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

  6. 获取/设置消息队列的属性信息

    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中获取到的属性信息

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

    • 通过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 
#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 
");_exit(-1);}struct mq_attr mq;//获取消息队列的各个属性if (mq_getattr(mq_id ,&mq)  == -1 ){ _exit(-1);}printf("mq_flags %ld
",mq.mq_flags); //mq_open默认将当前属性忽略,则一般为0printf("mq_maxmsg %ld
",mq.mq_maxmsg); //消息队列可以接收的最大消息容量为10个,当达到10个,则当前进程阻塞printf("mq_msgsize %ld
",mq.mq_msgsize); //每个消最大容量printf("mq_curmsgs %ld
",mq.mq_curmsgs);int ret;if ((ret = fork()) == -1) { printf("fork failed 
");_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 
");_exit(-1);}printf("child process receive msg :%s 
",msg_buf);sleep(1);}}else { while(1) { //父进程用来发送消息队列的信息,并设置发送的消息优先级为1//如果父进程发送多个优先级消息,子进程指定具体的一个优先级消息进行接收即可if (mq_send(mq_id,"hello world",sizeof("hello world"),1) == -1) { printf("mq_send failed
");_exit(-1);}printf("parent process :send msg to mqueue success
");sleep(1);}}//关闭当前进程对消息队列 mq_id的引用mq_close(mq_id);sleep(5);//引用计数为0时,删除当前进程创建的消息队列if(mq_unlink("/posix_msgqueue") == -1) { printf("mq_unlink failed
");_exit(-1);}return 0;
}

输出如下:

在这里插入图片描述

消息队列属性设置实例

我们知道如下三个参数,POSIX消息队列默认的属性值为

mq_flags = 0
mq_maxmsg = 10
mq_msgsize = 8192

通过如下代码可以分别看到mq_openmq_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;//将需要设置对属性参数设置为addrmq_id = mq_open("/notify",O_WRONLY | O_CREAT, 0666, &addr);if (mq_id == -1) { printf("mq_open failed
");	_exit(-1);}if (mq_getattr(mq_id,&addr) == -1) { printf("mq_getattr failed
");_exit(-1);}//打印最终对设置结果printf("mq_open set mq_flags = %ld
",addr.mq_flags);printf("mq_open set mq_maxmsg = %ld
", addr.mq_maxmsg);printf("mq_open set mq_msgsize = %ld
", 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 
");_exit(-1);}if (mq_getattr(mq_id,&attr) == -1) { printf("mq_getattr failed
");_exit(-1);}printf("mq_setattr set mq_flags = %ld
",attr.mq_flags);printf("mq_setattr set mq_maxmsg = %ld
", attr.mq_maxmsg);printf("mq_setattr set mq_msgsize = %ld
", 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 消息队列我们知道消息队列中在消息个数达到了队列所能承载的上限,就会发生消息的写阻塞。 阻塞式的通信影响系统效率,进程之间在通信收到阻塞时并不能去做其他事情,而是一直处于阻塞状态。 为了避免出现这样的低效问题,POSIX消息队列推出如下接口实现异步通信机制 函数头文件#include

  • 首先对微擎的工作原理做简单描述, 微擎使用规则和模块的机制来处理公众平台的请求数据并返回响应的结果.执行流程描述为: 粉丝用户与公众号码进行对话或交互, 而后公众平台将粉丝用户的请求消息(当前包括: 文本, 图片, 位置, 链接, 事件. 请参阅消息类型)传递给微擎系统, 微擎系统按照消息类型和对应的公众号所设定的规则列表匹配到合适的...

  • 消息队列的使用场景以下介绍消息队列在实际应用常用的使用场景。异步处理、应用解耦、流量削锋和消息通讯四个场景。1】异步处理:场景说明:用户注册后,需要发注册邮件和注册短信。引入消息队列后架构如下:用户的响应时间=注册信息写入数据库的时间,例如50毫秒。发注册邮箱、发注册短信写入消息队列后,直接返回客户端,因写入消息队列的速度很快,基...

  • 下面是我凭记忆想到的几个题目,有需要的同学就拿去吧,我也算做了点善事. 中体骏彩C++笔试题 2013-11-18 1.指针的含义是:B A.名字 B.地址 C.名称 D.符号 2.给出下面的程序输出: #include #include #include ...

  • 双端通信描述 利用消息队列针对发送接受消息的类型唯一性 进行多个客户端之间消息传递,而不需要server端进行消息转发。 同时消息队列的读阻塞和写阻塞特性(消息队列中已经写入数据,如果再不读出来,则无法再次写入)让消息队列的实现过程只能如下: 客户端1的父进程用来处理类型1的消息写,子进程处理类型2的消息读客户端2的父进程处理类型...

  • 文章目录基本介绍编程接口代码实例消息队列的发送和接收消息队列中的消息对象的属性控制 基本介绍 支持不同进程之间以消息(messages)的形式进行数据交换,消息能够拥有自己的标识,且内核使用链表方式进行消息管理。进程之间的通信角色为:发送者和接受者 发送者: a. 获取消息队列的ID(key或者msgid) b. 将数据放入...

  • 使用队列实现栈的下列操作: push(x) – 元素 x 入栈pop() – 移除栈顶元素top() – 获取栈顶元素empty() – 返回栈是否为空 队列的特点:先入先出 栈的特点:后入先出 即我们每次添加元素到队列时,想要达到栈的效果,则需要调整当前元素到队列头部 方法一:双队列 一个临时队列保存push进去的元素,将...

  • Queue除了前面介绍的实现外,还有一种双向的Queue实现Deque。这种队列允许在队列头和尾部进行入队出队操作,因此在功能上比Queue显然要更复杂。下图描述的是Deque的完整体系图。需要说明的是LinkedList也已经加入了Deque的一部分(LinkedList是从jdk1.2 开始就存在数据结构)。   Deque在Q...

  • 网络流量队列优先级相关知识点 Qdisc(quick disconnect)快速分离,断开;是一种排队规则,实现对流量的优先级管理.   涉及随机公平队列,令牌桶过滤器,分层令牌桶,FIFO, /*  *CopyRight (c) 2014-02-05 by Ruiy use to CopyLift!!!!  * */   ...