mosquitto源码分析(四)

  本文由逍遥子撰写,转发请标注原址:

http://write.blog.csdn.net/postedit/21463965

3.1.2、使用订阅树发布消息

在Mosquito程序中,消息发送过程主要通过遍历订阅树来完成,具体为:递归遍历订阅树找到指定的订阅列表,并将消息挂到订阅列表中的每个contextg的消息队列中,如果消息的retain字段被设置为1,则mosquitto还需要保存此消息,以备新订阅的客户端可以立即收到上次发送的消息;另外,发往系统topic的消息也会被mosquitto保存起来。上述消息发送过程主要通过函数mqtt3_db_messages_queue来完成。另外,根据mqtt协议,mosquitto还对#和+两个通配符提供支持,通配符#可放在topic的第一级之外的其他topic片段中,用以表示匹配所有后续topic片段,例如:a/# 可以匹配a/b、a/b/c、a等,但是#需要独立为一个分级才能起作用,即a/b#c/d这种情形不被支持。通配符用“+”用以匹配一级topic,例如a/+/c可以匹配a/b/c、a/d/c但是不能匹配a/d/f。另外消息的qos等级不同,mosquitto对消息的发送过程也不一样。

例如,在如图3-8所示的订阅树中, 以qos为0时发布消息为例,消息发布时通过mqtt3_db_messages_queue完成。

mosquitto源码分析(四)_第1张图片

图3-8 订阅树的遍历

向topic:year/month/events1发送消息,其发送过程为:

1) 将topic按照”/”分成topic片段:year、month、event1s三个topic片段;该topic分片过程在函数mqtt3_db_messages_queue中完成。

2) 遍历订阅树根的子节点,并根据第一级topic分片的类型是否为“$SYS”选择业务子树还是系统子树进行递归遍历。同时还需判断消息中retain标识位是否设置为1,如果是,则需将该topic的所有后续分片加入到订阅树中,经过该添加之后,订阅树中就存在了该topic,这一添加topic片段的过程在函数_sub_add中完成。

3) 递归遍历子树,每次选取一个topic分片,将之与当前的节点的所有子节点进行比较,以找到匹配的节点,然后继续递归匹配下去,递归处理过程主要由函数_sub_search完成;

4) 当匹配完所有的topic分片或者遇到topic分片为#时,进行如下处理:

5) 当消息的retain字段被设置为1之后,需要将该消息持久化,即保存下来,以备有新订阅者订阅该topic的消息时可以收到上一条消息。

6) 遍历当前订阅树节点的订阅列表,将消息挂载所有订阅者的消息队列中,此过程通过函数mqtt3_db_message_insert完成。

mosquitto消息发送过程中所调用函数的关系如下图3-9所示:

mosquitto源码分析(四)_第2张图片

图3-9          消息发布函数调用关系图

3.1.3、从订阅树中删除订阅客户端

在Mosquitto程序中,客户端可以向mosquitto服务器发送取消对某个topic的订阅请求,服务器收到请求之后,将从订阅树中删除该客户端,该过程需要遍历订阅树以找该topic在订阅树中的位置,进而获得到订阅该topic的订阅列表,从而将其从订阅树中删掉。该过程与发送消息类似,首先将topic进行分片,然后根据topic片段遍历订阅树找到该topic的订阅列表;然后遍历订阅列表,将该客户端从订阅列表中删除。

取消订阅的函数调用关系如图3-10所示。

mosquitto源码分析(四)_第3张图片

图3-10 取消订阅函数调用关系

3.1.4、订阅树机制的优缺点分析

Mosquito程序采用订阅树形式维护客户端之间的订阅与发布消息,这种方式优点是逻辑清晰,便于开发和维护。缺点是其遍历过程效率较低。同时,程序中存在很多对订阅树的遍历过程:订阅、发布消息、取消订阅等,在客户端数量增加时,该功能对效率的影响将更为明显。

因此,在mosquitto的实际应用中很难支持5万以上的客户端,尤其在客户端网络状态不好时,其断开重练操作将非常频繁,这样也造成大量对订阅树的遍历操作,从而严重影响mosquitto的效率。

3.2、mosquitto的消息收发机制

Mosquito最主要的功能就是对消息的正确接收、维护和转发,因此其消息的接、收功能非常重要。Mosquitto的消息收发主要通过poll机制来完成。

 

你可能感兴趣的:(mosquitto源码分析(四))