订阅树的概念
        Mosquitto通过订阅树的方式来管理所有的topic以及客户端的订阅关系,它首先将所有的topic按照/分割并组织成一棵树结构,从根节点到树中的每个节点即组成该节点所对应的一个topic,每个topic都保存一个订阅列表,该订阅列表中保存了所有订阅当前topic的客户端信息。例如有如下订阅关系:
客户端a1,a2,a3订阅了topic:A1/B1/C1m
客户端b1,b2订阅了topic:A2/B2/C2
客户端c1,c2订阅了topic:A1/B1/C3
客户端d1订阅了topic:A2/B3

则上述订阅树如图。

 

Mosquitto程序在实现中根据topic消息的性质将订阅树分为两颗子树:业务子树和系统子树;mosquitto程序中将topic分为两种类型来处理:系统topic和业务topic,前者主要用于发布和维护mosquitto内部的系统消息,后者的topic是用户订阅的业务topic,做这种区分的原因是因为这两种的类型的topic性质和实现方式上有许多差别,这种差别主要体现在以下3点:

1)生存周期不同,系统topic无论是否有用户订阅都会存在与订阅树中,而业务topic必须有客户端订阅才能存在(除非其消息字段retain设置为1)。

2)创建方式不同,系统topic在消息发布时进行创建,业务topic即可以在订阅时创建也可以在消息发布时创建(此时需要该消息retain字段设置为1)。

3)消息保存方式不同,凡是发布到系统topic的消息都会被保存下来,业务消息将直接挂到订阅列表的各context的消息队列中,如果没有连接订阅或未设置其retain字段,消息将不会被保存下来,消息的retain字段是否被设置在函数mqtt3_handle_publish进行检查。

订阅树的创建:(在src/database.c中的mqtt3_db_open函数实现)

mosquitto程序启动时将创建订阅树,该过程将创建三个节点:订阅树总根节点、业务子树根节点和系统子树根节点,这两个子树根节点作为订阅树总根节点的两个子节点,其中订阅树总根节点和业务子树的根节点中topic成员的值为空字符串,而系统子树根节点中保存的值为“$SYS”,如图:

 订阅树采用孩子兄弟链表法保存,确切来说应该是说业务子树和系统子树都是采用孩子兄弟链表法保存,而这两个节点还是作为总树根节点的两个子节点。

搭建订阅树    
1)
  系统子树搭建过程  
        Mosquitto中,系统子树在发布系统消息时,自动检测topic片段是否存在,如果不存在则在系统topic上创建节点以搭建订阅树。搭建过程如下:
将Topic按照“/"分成 topic片段;根据第一个topic片段“$SYS”遍历订阅树的子节点找到系统子树的根节点;根据topic下一个片段查找系统子树,若没有则创建这个节点,依次方案处理直至topic片段解析完。
       所用到的函数调用: mqtt3_db_messages_easy_queue(在src/database.c中)  --->mqtt3_db_messages_queue (在src/subs.c中) --->  _sub_add(在src/subs.c中)

2)业务子树搭建过程
      分为两种类型:订阅时创建和消息发布时创建。后者与系统Topic的方式类似。前者在收到订阅请求后将该客户端挂到对应的业务子树节点的订阅列表中,若不存在客户端所订阅的Topic,则会自动为之添加相应节点。
所用到的函数调用: mqtt3_handle_subscribe(在src/read_handle_server.c中) --->mqtt3_sub_add(在src/subs.c中) --->_sub_add(在src/subs.c中)

可以看到,在上面都使用了_sub_add函数,而调用它的分别是mqtt3_db_messages_queue 和mqtt3_sub_add函数,而且这三个函数都是在src/subs.c中,不妨来看看它们的逻辑。
mqtt3_db_messages_queue:(系统子树的搭建)

mqtt3_sub_add(业务子树的搭建)

 
 _sub_add:

这几张图把订阅树的构建的大致逻辑勾勒出来。可以看见业务子树和系统子树的搭建大致逻辑相似,但是在局部处理上还是有区别,最大的区别就是如果创建业务子树的时候如果有没有找到topic片段,则会向订阅树中添加相应节点,而创建系统子树时则不会(原因见前面提到的二者的区别的第二点)。
      还有就是这里在根据用户发布的topic(一个字符串)来在树结构中查询,用到了一个技巧,就是调用_sub_topic_tokenise函数将这个字符串分解,并组成一个链表的形式,然后通过遍历这个链表逐步完成对树结构的查询、添加等工作,最后释放掉这个链表。这里的链表就相当于一个缓冲区,值得借鉴。
例如一个Topic: year/month/day
就被转换为如下链表结构:

 

Mosquitto --topic的更多相关文章

  1. 五、Mosquitto 高级应用之权限管理

    本文将讲解 Mosquitto 权限管理.如果还没有搭建 Mosquitto 服务的可以参考我的另外两篇文章<< 一.Mosquitto 介绍&安装>> << ...

  2. mosquitto --用户配置 及权限管理

    mosquitto中可以添加多个用户,只有使用用户名和密码登陆服务器才允许用户进行订阅与发布操作.可以说用户机制是mosquitto重要的安全机制,增强服务器的安全性.用户与权限配置需要修改3处地方: ...

  3. mosquitto -- 权限配置

    Mosquitto 权限是根据 topic 控制的.类似与目录管理.您可以设定每个用户订阅/发布权限.也可以设定每个用户可访问的topic范围.从而达到权限控制的目的. 这里我们需要我另外一个帖子(用 ...

  4. mosquitto $SYS下topic

    $SYS/broker/clients/connected

  5. Mosquitto搭建Android推送服务(四)Mosquitto服务器用户登录与权限配置

    文章钢要: 1.对服务器进行多用户配置 2.根据不同用户给予不同权限 一.Mosquitto的用户机制 mosquitto中可以添加多个用户,只有使用用户名和密码登陆服务器才允许用户进行订阅与发布操作 ...

  6. Mosquitto搭建Android推送服务番外篇一:各种报错解决

    文章钢要: 目前笔者在开发搭建Mosquitto服务器,在此期间遇到很多实际问题,所以走了很多弯路,在这里写出来为大家提供一些帮助. 1.安装完成后启动Mosquitto报错 执行mosquitto客 ...

  7. Mosquitto搭建Android推送服务(三)Mosquitto集群搭建

    文章钢要: 1.进行双服务器搭建 2.进行多服务器搭建 一.Mosquitto的分布式集群部署 如果需要做并发量很大的时候就需要考虑做集群处理,但是我在查找资料的时候发现并不多,所以整理了一下,搭建简 ...

  8. Mosquitto搭建Android推送服务(一)MQTT简介

    总体概要: MQTT系列文章分为4部分 1.MQTT简介 2.mosquitto服务器搭建 3.编写Mosquitto的可视化工具 4.使用Mosquitto完成Android推送服务 文章钢要: 对 ...

  9. 借助mosquitto“实时”远程监控服务器数据库运行状态

    公司的项目还处于开发阶段,我把整个后台服务临时放在阿里云上供前端测试,用的阿里云的ECS云服务器,HTTP请求服务器和数据库服务都安装在一台机子上(穷啊,凑合用),做测试用,配置相当低:单核1Gb.其 ...

随机推荐

  1. URAL 1099 Work Scheduling (一般图最大匹配) 模板题【带花树】

    <题目链接> <转载于 >>>  > 题目大意: 给出n个士兵,再给出多组士兵之间两两可以匹配的关系.已知某个士兵最多只能与一个士兵匹配.求最多能够有多少对匹 ...

  2. HDU 4027 Can you answer these queries【线段树】

    <题目链接> 题目大意: 给定一段序列,现在对指定区间进行两种操作:一是对指定区间进行修改,对其中的每个数字都开根号(开根号后的数字仍然取整):二是对指定区间进行查询,查询这段区间所有数字 ...

  3. hdu 3001 Travelling (三进制)【状压dp】

    <题目链接> 题目大意: 给出n个点和m条边,求经过所有点所需的最小花费,每个点最多经过两次. 解题分析: TSP问题类型,由于此题每个点有三种状态,所以采用三进制状态压缩,0.1.2 分 ...

  4. Spring AOP 切面编程实战Demo项目

    为什么会有此项目?在某日,我看博客时,看到了讲面向切面编程的内容,之前也知道spring是面向切面编程的,只是自己没有写过相关的代码,于是决定自己写一个test.但是url拦截器从外部看,和AOP有相 ...

  5. springboot整合视图层之Thymeleaf

    Thymeleaf中有自己的表达式,和自己的语法,可以把数据取出来后再进行判断,遍历等操作,另外它还封装了strings,dates....对象,可以利用这些对象对已有的数据进行简单的逻辑处理: 1. ...

  6. 146. 大小写转换 II

    146. Lowercase to Uppercase II Description Implement an upper method to convert all characters in a ...

  7. DataGrid绑定DataTable出错

    直接用DataGrid.ItemSource = DataTable.DefaultView时会出现以下错误: target element is 'TextBlock' (Name=''); tar ...

  8. BZOJ.1109.[POI2007]堆积木Klo(DP LIS)

    BZOJ 二维\(DP\)显然.尝试换成一维,令\(f[i]\)表示,强制把\(i\)放到\(a_i\)位置去,现在能匹配的最多数目. 那么\(f[i]=\max\{f[j]\}+1\),其中\(j& ...

  9. 洛谷 P2814 家谱(gen)

    题目背景 现代的人对于本家族血统越来越感兴趣. 题目描述 给出充足的父子关系,请你编写程序找到某个人的最早的祖先. 输入输出格式 输入格式: 输入由多行组成,首先是一系列有关父子关系的描述,其中每一组 ...

  10. window下安装PIL

    PIL非官方库64 友情连接: https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/ ...