Linux系统编程4:IPC消息队列

Linux系统编程4:IPC消息队列

  • 0. 消息队列
  • 1. POSIX 消息队列
    • 1.1 查看
    • 1.2 接口
    • 1.3 结构体
    • 1.4 函数
      • 1.4.1 创建消息队列
      • 1.4.2 删除消息队列
      • 1.4.3 打开消息队列
      • 1.4.4 关闭消息队列
      • 1.4.5 发送消息
      • 1.4.6 接收消息
      • 1.4.7 设置消息队列属性
      • 1.4.8 获取消息队列属性

0. 消息队列

  • 背景
    管道和套接字比较适合两三个进程之间的通信,如果进程成倍增加,管道和套接字的数量也会阶乘级的增加,管理也非常复杂麻烦。于是出现的消息队列

  • 比喻
    回转寿司

  • 优先级
    让列宁同志先走

  • 本质
    内核链表

1. POSIX 消息队列

在这里插入图片描述

1.1 查看

  • POSIX消息队列预览:man mq_overview
  • 查看POSIX消息队列:ls /dev/mqueue
  • cat /dev/mqueue/PIC名字

1.2 接口

  • 头文件:mqueue.h
  • 库:librt.so(real time)

1.3 结构体

  • struct mq_attr消息队列属性
    在这里插入图片描述

1.4 函数

POSIX 消息队列主要有八个操作
在这里插入图片描述
*消息队列操作非常相似文件读写操作

1.4.1 创建消息队列

mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr)
  • 参数
    在这里插入图片描述
  • 标志
    在这里插入图片描述
  • 权限
    在这里插入图片描述
  • 返回值
    在这里插入图片描述
  • 示例
    创建一个名字为/tmp.test的POSIX 消息队列
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open()
#define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) //0644
int main(){
    struct mq_attr attr;
    attr.mq_maxmsg = 100;
    attr.mq_msgsize = 100;
    mqd_t mqd = mq_open("/tmp.test",O_CREAT,FILE_MODE,&attr);
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
}

注意编译时可能需要加上 -lrt

  • 注意
      POSIX消息队列的名字所创建的真正路径名和具体的系统实现有关,关于具体POSIX IPC的名字规则可以参考《UNIX 网络编程 卷2:进程间通信》。在Redhat所创建的POSIX消息队列不会在文件系统中创建真正的路径名。且POSIX的名字只能以一个/开头,名字中不能包含其他的/

1.4.2 删除消息队列

int mq_unlink(const char *name)
  • 参数
    在这里插入图片描述
  • 返回值
    在这里插入图片描述
  • 示例
    删除POSIX消息队列
#include <mqueue.h> // mq_unlink()
int main(){
    mq_unlink("/tmp.test");
}

1.4.3 打开消息队列

mqd_t mq_open(const char *name, int oflag)
  • 参数
    在这里插入图片描述

  • 返回值
    在这里插入图片描述

  • 示例

#include <stdio.h> // perror()
#include <mqueue.h> // mq_open()
int main(){
    mqd_t mqd = mq_open("/tmp.test",O_RDONLY);
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    return 0;
}

1.4.4 关闭消息队列

int mq_close(mqd_t mqdes)
  • 参数
    在这里插入图片描述
  • 返回值
    在这里插入图片描述
  • 示例
    关闭消息队列
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_close()
int main(){
    mqd_t mqd = mq_open("/tmp.test",O_RDONLY);
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    // ...
    mq_close(mqd);
}
  • 注意
    mq_close()和文件的close()类似,关闭后,消息队列并不从系统中删除。一个进程结束,会自动调用关闭打开着的消息队列。

1.4.5 发送消息

int mq_send(mqd_t mqdes, const char *msg_ptr,size_t msg_len, unsigned msg_prio)
  • 参数
    在这里插入图片描述
  • 示例
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_send() mq_close()
int main(int argc,char* argv[]){
    mqd_t mqd = mq_open("/tmp.test",O_WRONLY); // 可以设置O_NONBLOCK
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    const char* msg = "HelloWorld";
    if(-1 == mq_send(mqd,msg,sizeof(msg),1)){
        perror("mq_send error");
        mq_close(mqd);
        return 1;
    }
    mq_close(mqd);
    return 0;
}
  • 问题
  1. 如果发送的消息长度超过mq_msgsize会怎样?
  2. 如果发送的消息个数超过mq_maxmsg会怎样?
  • 注意
    消息在队列中将按照优先级大小顺序来排列消息
    消息队列已满,mq_send()函数将阻塞,直到有可用空间再次允许放置消息。
    如果O_NONBLOCK被指定,mq_send()那么将不会阻塞,而是返回EAGAIN错误。

1.4.6 接收消息

ssize_t mq_receive(mqd_t mqdes, char *msg_ptr,size_t msg_len, unsigned *msg_prio)
  • 参数
    在这里插入图片描述
  • 返回值
    在这里插入图片描述
  • 示例
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_receive() mq_close()
#define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) //0644
int main(int argc,char* argv[]){
    mqd_t mqd = mq_open("/tmp.test",O_RDONLY);
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    char buf[BUFSIZ];
    unsigned int prio;
    if(-1 == mq_receive(mqd,buf,BUFSIZ,&prio)){
        perror("mq_send error");
        mq_close(mqd);
        return 1;
    }
    printf("msg:%s\nprio:%d\n",buf,prio);
    mq_close(mqd);
    return 0;
}
  • 注意
  1. POSIX消息队列在调用mq_receive()时总是返回队列中最高优先级的最早消息。
  2. 如果队列空,mq_receive()函数将阻塞,直到消息队列中有新的消息。
  3. 如果O_NONBLOCK被指定,mq_receive()那么将不会阻塞,而是返回EAGAIN错误。

1.4.7 设置消息队列属性

int mq_setattr(mqd_t mqdes, struct mq_attr *newattr,struct mq_attr *oldattr);
  • 参数
    在这里插入图片描述
  • 返回值
    在这里插入图片描述
  • 示例
#include <stdio.h> // perror()
#include <string.h> // bzero()
#include <mqueue.h> // mq_open() mq_setattr() mq_close()
int main(){
    mqd_t mqd = mq_open("/tmp.test",O_RDWR);
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    struct mq_attr new_attr;
    bzero(&new_attr,sizeof(new_attr));
 
    new_attr.mq_flags = O_NONBLOCK;
    struct mq_attr attr;
    if(-1 == mq_setattr(mqd,&new_attr,&attr)){
        perror("mq_setattr error");
        mq_close(mqd);
        return 1;
    }
    printf("flag:%ld,Max msg:%ld,Max msgsize:%ld,Cur msgnun:%ld\n",attr.mq_flags,attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
    mq_close(mqd);
}

1.4.8 获取消息队列属性

int mq_getattr(mqd_t mqdes, struct mq_attr *attr)
  • 参数
    在这里插入图片描述
  • 返回值
    在这里插入图片描述
  • 示例
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_getattr() mq_close()
int main(){
    mqd_t mqd = mq_open("/tmp.test",O_RDONLY);
    if(-1 == mqd){
        perror("mq_open error");
        mq_close(mqd);
        return 1;
    }
    struct mq_attr attr;
    mq_getattr(mqd,&attr);
    printf("flag:%ld,Max msg:%ld,Max msgsize:%ld,Cur msgnun:%ld\n",attr.mq_flags,attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
   mq_close(mqd);
    return 0;
}
  • 注意
  1. mq_setattr()可以设置的属性只有mq_flags,用来设置或清除消息队列的非阻塞标志。
  2. newattr结构的其他属性被忽略。
  3. mq_maxmsgmq_msgsize属性只能在创建消息队列时通过mq_open()来设置。
  4. mq_open()只会设置该两个属性,忽略另外两个属性。
  5. mq_curmsgs属性只能被获取而不能被设置。

热门文章

暂无图片
编程学习 ·

Java的ConcurrentHashMap 底层了解

最近有人问Java8 中ConcurrentHashMap 底层实现,这里简单列下。大家都知道 Java8 对 HashMap 、ConcurrentHashMap 进行了改进,前者非线程安全,后者线程安全。HashMap在Java 7 中,采用哈希表结构在Java 8 中,采用哈希表 + 红黑树ConcurrentHashMap在Java 7 中,采用分段的…
暂无图片
编程学习 ·

实战系列-Spring Cloud微服务中三把利器Feign、Hystrix、Ribbon

导语在之前的分享中分享过关于Fegin的底层实现原理,以及Spring Cloud OpenFegin的启动原理。在这次的分享中主要总结一下Spring Cloud 微服务架构的三把利器。对于Fegin、Hystrix、Ribbon三个组件来说它们之间是什么样的关系。怎么样综合使用等这些问题就是这次分享的内容文章…
暂无图片
编程学习 ·

2020年陆月份生活随笔

今天是建党99年,党的生日,不是党员,要按照党员的标准严格要求自己。昨天看了一下月跑量,计划着跑一个总里程171.99,计算了一下今天跑一个8.48就可以,今天跑步特意戴上耳机听跑步软件播报公里数,到了八公里就放满了速度,跑着距离感觉快到了,心想过了这个路口再看手机,…
暂无图片
编程学习 ·

如何用Nearby Service开发针对附近人群的精准广告推送功能

当你想找一家餐厅吃饭,却不知道去哪家,这时候手机跳出一条通知,为你自动推送附近优质餐厅的信息,你会点击查看吗?当你还在店内纠结于是否买下一双球鞋时,手机应用给了你发放了老顾客5折优惠券,这样的广告你有拒绝的理由吗?这样的广告不仅不会引起用户的厌烦,还满足了用…
暂无图片
编程学习 ·

为什么 SELECT * 效率低?

面试官:“小程,说一下你常用的SQL优化方式吧。” 程序猿小一:“那很多啊,比如不要用SELECT *,查询效率低。巴拉巴拉…” 面试官:“为什么不要用SELECT * ?它在哪些情况下效率低呢?” 程序猿小一:“SELECT * 它好像比写指定列名多一次全表查询吧,还多查了一些无用的字…
暂无图片
编程学习 ·

python向json文件中追加内容

我们常常会遇到这样的json文件: [{"id": 4, "text": "LOC", "background_color": "#7c20e0", "text_color": "#ffffff"}, {"id": 5, "text": "MISC", "background…
暂无图片
编程学习 ·

C 语言为什么不会过时?

01、为什么C语言不会过时 评价任何一门编程语言,都是招人骂的。永远是这样。就像是春寒料峭的季节,街上穿棉袄和穿单衣的擦肩而过,双方一定是同时在心里出现了两个字:“傻逼!”这个在心理学上有个专业的名字:叫做“二逼”现象! 那我为啥还要做这个挨骂的事呢?作为《C语…
暂无图片
编程学习 ·

设计模式-建造者模式

设计模式-建造者模式 1.问题提出 盖房项目需求需要建房子:这一过程为打桩、砌墙、封顶 房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的. 请编写程序,完成需求.2.传统方式解决 package builder.traditional;public abstract class Ab…
暂无图片
编程学习 ·

寻找凸包(Graham扫描法)

寻找凸包(Graham扫描法)题意描述对任意给定的平面上的点集,求最小凸多边形使得点集中的点要么在凸多边形的边上,要么在凸多边形的内部。Graham算法描述 1、在所有的点中找到一点p0,使得p0的纵坐标值最小,在有多个最小纵坐标的情况下,找横坐标最小的那一个。 2、将所有的…
暂无图片
编程学习 ·

ISIS DIS(学习笔记+实验验证)

ISIS DIS原理概述实验一,实验目的二,实验内容(一)实验拓扑(二)配置步骤1,基本配置2,配置IS-IS路由协议3,查看默认选举的DIS4,修改DIS优先级来控制DIS选举结果 原理概述 OSPF协议支持四种网络类型IS-IS只支持两种:广播网络和点到点网络 与OSPF协议相同,IS-IS协议会在…
暂无图片
编程学习 ·

05 | 消息积压了该如何处理?

1.应用场景https://blog.csdn.net/william_n/article/details/1040254082.学习/操作2.1 阅读文档这节课我们来聊一聊关于消息积压的问题。据我了解,在使用消息队列遇到的问题中,消息积压这个问题,应该是最常遇到的问题了,并且,这个问题还不太好解决。我们都知道,消息积压…
暂无图片
编程学习 ·

OpenCV联通域检测 connectedComponentsWithStats

文章目录函数介绍C++ 代码示例Python 代码示例函数介绍 输入必须是单通道图像,最好是二值图 int cv::connectedComponents (cv::InputArrayn image, // input 8-bit single-channel 二值图cv::OutputArray labels, // output label mapint …
暂无图片
编程学习 ·

隐秘的角落:张东升的人生,给所有职场人提了个醒

如果说,找一个代名词来形容职场中的中年人,之前可能没有。现在,我想,“张东升”这三个字就够了! 张东升是近期大火的电视剧《隐秘的角落》的主角,在剧中,他有着两种截然不同的模样。 表面上,在学生眼里他是一个才华横溢、带来梦想的数学老师,在同事眼里他是一个忠于妻…
暂无图片
编程学习 ·

一起Talk Android吧(第二百五十五回:Android中的Toolbar标题一)

各位看官们大家好,上一回中咱们说的是Android中Toolbar的例子,这一回咱们继续说该例子。闲话休提,言归正转。让我们一起Talk Android吧! 看官们,我们在前面章回中介绍完了Toolbar的导航,本章回中将介绍Toolbar的标题。标题位于导航右侧,用来提示程序的内容或者当前页面的…
暂无图片
编程学习 ·

路由策略与路径控制

一.Passive-interface 1. RIP/IGRP 在指定接口不向外发送路由更新,但是接收路由更新 2. EIGRP 在指定接口不向外发送Hello消息,而且通过这个接口不与其他路由器建立邻居关系,不发送其他EIGRP的数据流 3. OSPF 在指定接口不向外发送Hello消息,而且通过这个接口不与其他路由器…
暂无图片
编程学习 ·

【Docker】 Docker pull的时候指定仓库

1.概述 默认情况下docker pull会从docker hub拉取镜像文件,也可以手动指定一个仓库地址拉取镜像。假如你设置了一个本地仓库地址,那么你只要指定这个地址拉取镜像即可。仓库地址类似一个URL,但是没有协议头http://。 例如从一个镜像地址:myregistry.local:5000,拉取镜像文…
暂无图片
编程学习 ·

Vue循环渲染&key的原理

v-for用于循环的数组里面的值可以是对象,也可以是普通元素<ul id="example-1"><!-- 循环结构-遍历数组 item 是我们自己定义的一个名字 代表数组里面的每一项 items对应的是 data中的数组--><li v-for="item in items">{{ item.mess…