美文网首页IPC
消息队列总结

消息队列总结

作者: madao756 | 来源:发表于2019-12-11 11:13 被阅读0次

前言:进程间通信的另一大重点,但是难度也不大,废话不多说,让我们开始

0X00 消息队列介绍

内核中一个消息队列表示的方式如下:

  • 首先消息队列是一个链表的方式存在,和管道不同
  • 头部消息记录着这个消息队列最大长度(mq_maxsmsg),以及最大消息长度(mq_msgsize)

其中优先级小的就在前面,优先级大的在后面

0X01 与消息队列相关的函数

消息队列涉及的 api 有很多,尽量用多的例子来演示这些 api

创建 打开 关闭 删除

  • mg_open 函数创建一个新的消息队列或者打开一个已存在的消息队列
#include <mqueue.h> 

mqd_t mq_open(const char *name, int oflag, ...
              /*mode_t mode, struct mq_attr* attr/) 

当实际操作是一个新队列时,mode 和 attr 是必须的,如果是打开一个消息队列则不需要

我们来说说每个参数的含义:

  1. name

指队列的名称

  1. oflag

是队列的 flag,比如 O_RDONLY 就是只接受消息;O_WRONLY 只发送消息;O_RDWR 表示又可以读又可以写;O_NONBLOCK 就是在非阻塞的情况下使用该队列。

在没有设置非阻塞的情况下,如果队列满了,mq_send() 就会阻塞,而如果队列是空的,mq_receive 也会阻塞

  1. mode

mode 定义了队列的权限

  1. attr

attr 指向了一个 mq_attr 的结构体,定义如下:

struct mq_attr {
    long mq_flags;       /* Flags: 0 or O_NONBLOCK */
    long mq_maxmsg;      /* Max. # of messages on queue */
    long mq_msgsize;     /* Max. message size (bytes) */ 
    long mq_curmsgs;     /* # of messages currently in queue */
};         

其中 mq_maxmsg 的值应该小于等于 /proc/sys/fs/mqueue/msg_max 里面的值(默认是 10),mq_msgsize 的值应该小于等于/proc/sys/fs/mqueue/msgsize_max 里面的值(默认 8192)这些限制可能被特殊进程忽略

如果 mq_open 调用成功,则返回消息队列描述符消息队列描述符可以在队列的后续调用中使用。

  • mq_close 函数关闭消息队列描述符
#include <mqueue.h>

int mq_close (mqd_t mqdes);

其功能与关闭一个已经打开文件的 close 函数类似,但是并不会从系统中删除,

一个进程终止时,它所有打开着的消息队列都会关闭

  • mq_unlink 从系统中删除一个消息队列

每个消息队列都有一个保存当前打开着描述符数目的引用计数器,当计数大于 0 时,你只能删掉它的名字,但是它真正的析构要等到最后一个 mq_close

现在我们使用一个小程序验证上述的知识点:

#include "./unpipc.h"

int main(int argc, char **argv)
{
    int c, flags;
    mqd_t mqd;

    if (argc != 2)
        perror("usage: mqcreate  <name>");

    flags = O_RDWR | O_CREAT;
    mqd = mq_open(argv[1], flags, FILE_MODE, NULL);

    if(mqd == -1) {
        perror("mq_open fails");
    }
    // 关闭消息队列
    mq_close(mqd);
    // 删除消息队列
    int a = mq_unlink(argv[1]);
    if(a) {
        perror("mq_unlink fails");
    }
    return 0;
}

头文件地址:https://github.com/TensShinet/learn_IPC/blob/master/my_code/msg_queen/unpipc.h

在没有删除的情况下,可以去 /dev/mqueue 下查看,创建的消息队列

得到与设置消息队列相关属性

#include <mqueue.h>

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);

皆返回,若成功则为 0,若出错则返回 -1

我们在创建消息队列的时候,可以设置消息队列的属性,还可通过上述两个函数得到与修改消息队列的属性

看一个例子:输入一个消息队列的名字,输出它的属性

#include "./unpipc.h"

int main(int argc, char **argv)
{
    mqd_t mqd;
    struct mq_attr attr;

    if (argc != 2)
        perror("usage: mqgetattr <name>");

    mqd = mq_open(argv[1], O_RDONLY);

    mq_getattr(mqd, &attr);
    printf("max #msgs = %ld, max #bytes/msg = %ld, "
           "#currently on queue = %ld\n",
           attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);

    mq_close(mqd);
    exit(0);
}

头文件地址:https://github.com/TensShinet/learn_IPC/blob/master/my_code/msg_queen/unpipc.h

发送 接收

#include <mqueue.h>

int mq_send (mqd_t mqdes, const char *msg_ptr, size_t msg_len, 
             unsigned int msg_prio);
             
ssize_t mq_receive (mqd_t mqdes, char *msg_ptr, size_t msg_len, 
                    unsigned int *msg_prio);

这两个函数分别用于往一个队列中放置一个消息和从一个队列中取走一个消息,每一个消息都有一个优先级

它是一个小于 MQ_PRIO_MAX 的无符号整数 MQ_PRIO_MAX 至少为 32

  • mq_send 成功返回 0,出错返回 -1
  • mq_receive 成功返回消息中的字节数,出错返回 -1

还要注意一点的是:

mq_receive 的 len 参数不能小于队列中消息的最大大小(也就是 mq_msgsize 成员)

接下来我们使用已知消息队列发送与接收消息

  • send
#include "./unpipc.h"

int main(int argc, char **argv)
{
    mqd_t mqd;
    void *ptr;
    size_t len;
    unsigned int prio;

    if (argc != 4)
        perror("usage: mqsend <name> <#bytes> <priority>");
    len = atoi(argv[2]);
    prio = atoi(argv[3]);

    mqd = mq_open(argv[1], O_WRONLY);
    if (mqd == -1) {
        perror("mq_open");
    }
    
    ptr = calloc(len, sizeof(char));
    scanf("%s", (char *)ptr);

    int a = mq_send(mqd, ptr, len, prio);
    if(a == -1) {
        perror("mq_send");
    }
    mq_close(mqd);
    exit(0);
}
➜  msg_queen git:(master) ✗ gcc mqsend.c -o mqsend.out -lrt
➜  msg_queen git:(master) ✗./mqsend.out /mq2 10 10
LoveYou
  • receive
#include "unpipc.h"

int main(int argc, char **argv)
{
    mqd_t mqd;
    ssize_t n;
    unsigned int  prio;
    void *buff;
    struct mq_attr attr;

    mqd = mq_open(argv[1], O_RDONLY);
    if(mqd == -1) {
        perror("mq_open");
    }
    mq_getattr(mqd, &attr);

    buff = malloc(attr.mq_msgsize);

    n = mq_receive(mqd, buff, attr.mq_msgsize, &prio);
    printf("read %ld bytes, priority = %u mq_msgsize = %ld\n", (long)n, prio, attr.mq_msgsize);
    printf("read cotent: %s", (char *)buff);

    mq_close(mqd);

    return 0;
}
➜  msg_queen git:(master) ✗ ./mqreceive.out /mq2
read 10 bytes, priority = 10 mq_msgsize = 8192
read cotent: LoveYou%   

头文件地址:https://github.com/TensShinet/learn_IPC/blob/master/my_code/msg_queen/unpipc.h

对于消息队列的阻塞部分就是这么多的内容,对于消息队列的非阻塞部分,等学完后面的知识以后,我们继续完善

相关文章

  • 消息队列总结

    前言:关于消息队列应该大家都不陌生,在实际的项目中消息队列也无处不在,今天我和大家分享一下关于消息队列的问题。 1...

  • 消息队列总结

    前言:关于消息队列应该大家都不陌生,在实际的项目中消息队列也无处不在,今天我和大家分享一下关于消息队列的问题。 ...

  • 消息队列总结

    ##背景:做部门技术分享时,学习整理了消息队列。 一、应用场景 消息队列中间件是分布式系统中重要的组件。主要解决 ...

  • 消息队列总结

    前言:进程间通信的另一大重点,但是难度也不大,废话不多说,让我们开始 0X00 消息队列介绍 在内核中一个消息队列...

  • kafka总结

    Kafka史上最详细原理总结 - CSDN博客 总结: 消息队列的性能好坏,其文件存储机制设计是衡量一个消息队列服...

  • 消息队列mq总结

    一、消息队列概述 消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,...

  • RabbitMQ总结

    RabbitMQ总结 基础知识 为什么要用消息队列 队列是一种先进先出的数据结构。 消息队列是分布式系统中重要的组...

  • RabbitMQ实战:运行和管理RabbitMQ

    本系列是「RabbitMQ实战:高效部署分布式消息队列」书籍的总结笔记。 上一篇 介绍了AMQP消息通信,包括队列...

  • 消息队列:消息队列简介

    1. 什么是消息队列 消息队列(message queue),是一种应用程序的通信方法; 消息队列是 生产者-消费...

  • 消息队列与领域事件

    一年前做过两个比较肤浅的消息队列的总结,消息队列作用[https://www.jianshu.com/p/1ae3...

网友评论

    本文标题:消息队列总结

    本文链接:https://www.haomeiwen.com/subject/mzrogctx.html