-
2017-03-20 23:45:31
mosquitto 源代码中核心数据结构分析
一、struct mosquitto (在mosquitto_internel.h中定义)
struct mosquitto 这个结构体用来保存一个客户端连接的所有信息
这个结构体包含了很多成员,我们选取一些重要的成员,在代码中标注:
struct mosquitto { #ifndef WIN32 int sock; /*服务器程序与该客户端连接通信所用的socket描述符*/ # ifndef WITH_BROKER int sockpairR, sockpairW; # endif #else SOCKET sock; # ifndef WITH_BROKER SOCKET sockpairR, sockpairW; # endif #endif enum _mosquitto_protocol protocol; char *address;/*该客户端的IP地址*/ char *id;/*该客户端登陆mosquitto程序时所提供的ID值,该值与其他的客户端不能重复*/ char *username;/*登录用户名*/ char *password;/*密码*/ uint16_t keepalive;/*该客户端需在此时间内向mosquitto服务器程序发送一条ping/pong消息*/ uint16_t last_mid; enum mosquitto_client_state state; time_t last_msg_in;/*last_msg_in和last_msg_out用于记录上次收发消息的时间*/ time_t last_msg_out; time_t ping_t; struct _mosquitto_packet in_packet; struct _mosquitto_packet *current_out_packet; struct _mosquitto_packet *out_packet; struct mosquitto_message *will; ... bool want_write; bool want_connect; #if defined(WITH_THREADING) && !defined(WITH_BROKER) pthread_mutex_t callback_mutex; pthread_mutex_t log_callback_mutex; pthread_mutex_t msgtime_mutex; pthread_mutex_t out_packet_mutex; pthread_mutex_t current_out_packet_mutex; pthread_mutex_t state_mutex; pthread_mutex_t in_message_mutex; pthread_mutex_t out_message_mutex; pthread_t thread_id; #endif bool clean_session; #ifdef WITH_BROKER bool is_dropping; bool is_bridge; struct _mqtt3_bridge *bridge; struct mosquitto_client_msg *msgs;/*用于暂时存储发往该context的消息。*/ struct mosquitto_client_msg *last_msg; int msg_count; int msg_count12; struct _mosquitto_acl_user *acl_list; struct _mqtt3_listener *listener; time_t disconnect_t; struct _mosquitto_packet *out_packet_last; struct _mosquitto_subhier **subs; int sub_count; int pollfd_index; ... };
二、struct mosquitto_db (定义在mosquitto_broker.h)
struct mosquitto_db 结构体定义了对所有内部数据的统一管理,保存了所有客户端,订阅关系。可以认为是一个数据仓库。
struct mosquitto_db{ dbid_t last_db_id; struct _mosquitto_subhier subs;/*订阅树的总树根*/ struct _mosquitto_unpwd *unpwd; struct _mosquitto_acl_user *acl_list; struct _mosquitto_acl *acl_patterns; struct _mosquitto_unpwd *psk_id; struct mosquitto *contexts_by_id; /*所有的客户端都在此数组中保存*/ struct mosquitto *contexts_by_sock; struct mosquitto *contexts_for_free; #ifdef WITH_BRIDGE struct mosquitto **bridges; #endif struct _clientid_index_hash *clientid_index_hash; struct mosquitto_msg_store *msg_store; struct mosquitto_msg_store_load *msg_store_load; #ifdef WITH_BRIDGE int bridge_count; #endif int msg_store_count; struct mqtt3_config *config; /*保存配置信息*/ int persistence_changes; struct _mosquitto_auth_plugin auth_plugin; #ifdef WITH_SYS_TREE int subscription_count; int retained_count; #endif struct mosquitto *ll_for_free; };
三、struct _mosquitto_subhier(定义在mosquitto_broker.h)用来保存订阅树的所有节点,mosquitto中对订阅树采用孩子-兄弟链表法的方式进行存储
struct _mosquitto_subhier { struct _mosquitto_subhier *children;/*第一个孩子节点*/ struct _mosquitto_subhier *next;/*指向该节点的下一个兄弟节点*/ struct _mosquitto_subleaf *subs;/*指向订阅列表*/ char *topic;/*订阅主题*/ struct mosquitto_msg_store *retained; };
四、struct _mosquitto_subleaf (定义在mosquitto_broker.h)
对某一topic的所有订阅者被组织成一个订阅列表,该订阅列表是一个双向链表,链表的每个节点都保存有一个订阅者
struct _mosquitto_subleaf { struct _mosquitto_subleaf *prev;/*前指针*/ struct _mosquitto_subleaf *next;/*后指针*/ struct mosquitto *context;/*表示一个订阅客户端*/ int qos;/* Qos Level */ };
五、struct mqtt3_config (定义在mosquitto_broker.h)
保存mosquitto的所有配置信息,mosquitto程序在启动时将初始化该结构体并从配置文件中读取配置信息保存于该结构体变量内。
以上暂且先列出一些核心数据结构,其他数据结构用到时在分析。下篇结合使用方法来分析main程序。
更多相关内容 -
mosquitto源码分析
2018-10-20 18:45:22mosquitto是官方推荐的mqtt broker,此文档详细描述mosquitto的代码架构及插件定制原理 -
mosquitto源码分析.pdf
2021-10-02 12:02:39mosquitto源码分析.pdf -
mosquitto源码分析(一)
2014-03-18 15:22:26mosquitto是一款实现了消息推送协议MQTT v3.1 的开源消息代理软件,提供轻量级的,支持可发布/可订阅的的消息推送模式,使设备对设备之间的短消息通信变得简单,例如现在应用广泛的低功耗传感器,手关于mqtt、mosquito的技术交流,可入群:221779856
本文由逍遥子撰写,转发请标注原址:
http://blog.csdn.net/houjixin/article/details/21461225
一、 Mosquitto简介
mosquitto是一款实现了消息推送协议MQTT v3.1 的开源消息代理软件,提供轻量级的,支持可发布/可订阅的的消息推送模式,使设备对设备之间的短消息通信变得简单,例如现在应用广泛的低功耗传感器,手机、嵌入式计算机、微型控制器等移动设备。
Mosquitto采用出版/订阅的模式实现MQTT协议,这种设计模式将通信终端之间的关系统一到服务程序中进行管理,可极大减轻客户端的开发和维护工作。
1.1、 mqtt协议简介
MQTT(MessageQueuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。在某些应用场合中,可通过该协议维持与客户端的长连接。关于mqtt协议更详细的介绍,请参考其官方网站:http://mqtt.org/
其他版本源码下载位置:http://mosquitto.org/files/source/
1.2、 出版/订阅模式简介
出版/订阅模式定义了如何向一个节点发布和订阅消息,这些节点被称作主题(topic)。主题可以被认为是消息的传输中介,发布者(publisher)发布消息到主题,订阅者(subscriber) 从主题订阅消息。这种模式使得消息订阅者和消息发布者保持互相独立,不需要接触即可保证消息的传送。
Tcp协议中,tcp连接只提供一对一的可靠传输,例如:主机A与B进行通信,则发起tcp连接的一端只需要知道对方的ip地址和端口号即可,如下图1-1所示:
图1-1 一对一通信
每一个tcp连接都是由下面的五个元素确定:
<源ip地址,源端口号,目的ip地址,目的端口号,通信协议>
在实际程序的开发过程中 一条连接建立之后,它可能需要在一段时间内一直被通信双方所保持,以备下次数据传输使用。另外,通信的终端数目可能是多个,这就需要每个终端都要维持它所有的通信关系,如下图1-2所示
图1-2 多对多通信
此时,每个参与通信的客户端所需维持的连接数量将非常庞大,这非常不利于程序的开发和实现。出版/订阅模式即是一种解决这种问题的方法,它通过增加一个中间层的方式,让中间层来维护这种多对多的关系,这个中间层通常称之为服务器,如下图1-3所示:
图1-3 增加中间层的多对多通信
通过增加中间层服务器,每个客户端都只需要维护自己同服务器之间的连接即可,而客户端之间的关系则交由中间服务器来维护,这种设计模式将复杂的通信关系维护工作从客户端剥离出来,非常方便客户端的开发和维护。
Mosquito程序即是通过这种方式进行工作,在mosquitto程序内部,将客户端之间的关系通过一棵订阅树来维持。
1.3、 Mosquito
Mosquito源码目录结构介绍。
|---- mosquitto-1.2
|---- client
|---- examples
|----mysql_log
|----temperature_conversion
|---- installer
|---- lib
|---- cpp
|---- jsws
|----python
|---- logo
|---- man
|---- po
|----libmosquitto
|----mosquitto
|----mosquitto.conf
|----mosquitto_pub
|----mosquitto_sub
|----mosquitto-tls
|----mqtt
|---- misc
|----currentcost
|----gnome-panel
|---- security
|---- service
|---- monit
|----svscan
|----upstart
|---- src
|----db_dump
|---- test
|----broker
|---- c
|---- lib
|---- c
|----cpp
|----python
|----python3
|---- ssl
|----demoCA
|----rootCA
|----signingCA
所需关注的目录有/ mosquitto-1.2/src、/ mosquitto-1.2/lib、/ mosquitto-1.2/client三个目录,其中src和lib目录下主要放置mosquitto的实现代码以及部分底层与网络相关的操作,client目录主要为两个客户端程序的实现源码。
Mosquito的源码及其相关文档可从其官方网站获取,其官方网站为:http://mosquitto.org/
mosquitto客户端和服务器运行命令
[1] 发布者客户端运行命令示例:
./mosquitto_pub -h 192.168.6.243 -p 1883 -t "111" -m "this is jason.hou" -u 111 -P 111
[2] 订阅者客户端运行命令示例:
./mosquitto_sub -h 192.168.6.243 -i 111 -p 1883 -t 111 -k 60 -d -c -u hjx -P hjx
[3] mosquitto服务器端运行命令示例:
./mosquitto -
mosquitto源码分析(二)
2015-04-03 10:54:58本文由逍遥子撰写,转发请标注原址: http://write.blog.csdn.net/postedit/21462005 一、 Mosquito的数据结构 1) struct mosquito 结构体struct mosquito主要用于保存一个客户端...struct mosquitto {本文由逍遥子撰写,转发请标注原址:
http://write.blog.csdn.net/postedit/21462005
一、 Mosquito的数据结构
1) struct mosquito
结构体struct mosquito主要用于保存一个客户端连接的所有信息,例如用户名、密码、用户ID、向该客户端发送的消息等,其定义为:
struct mosquitto {
int sock;
char*address;
char *id;
char*username;
char*password;
uint16_tkeepalive;
time_tlast_msg_in;
time_tlast_msg_out;
struct mosquitto_client_msg *msgs;
…
}
上面列举了该结构体部分重要成员,其中sock表示mosquitto服务器程序与该客户端连接通信所用的socket描述符;address表示该客户端的IP地址;id是该客户端登陆mosquitto程序时所提供的ID值,该值与其他的客户端不能重复;成员username和password用于记录客户端登陆时所提供的用户名和密码;keepalive是该客户端需在此时间内向mosquitto服务器程序发送一条ping/pong消息。参数last_msg_in和last_msg_out用于记录上次收发消息的时间;参数struct mosquitto_client_msg*msgs用于暂时存储发往该context的消息。
2) struct mosquitto_db
结构体struct mosquitto_db是mosquitto对所有内部数据的统一管理结构,可以认为是其内部的一个内存数据库。它保存了所有的客户端,所有客户端的订阅关系等等,其定义形式为:
struct mosquitto_db{
dbid_tlast_db_id;
struct_mosquitto_subhier subs;
struct mosquitto**contexts;
struct_clientid_index_hash *clientid_index_hash;
intcontext_count;
structmosquitto_msg_store *msg_store;
intmsg_store_count;
structmqtt3_config *config;
intsubscription_count;
……
};
上述结构体声明中,结构体成员struct _mosquitto_subhier subs保存了订阅树的总树根,mosquitto中对所有的topic都在该订阅树中维护,客户端的订阅关系也在该订阅树中维护;结构体成员struct mosquitto **contexts可理解为一个用于存放所有客户端变量(类型为struct mosquitto)地址的数组,mosquitto程序中,所有的客户端都在此数组中保存;成员int context_count用于保存数组contexts的大小,该值也是当前mosquitto程序中维持的所有客户端的数目;成员结构体struct _clientid_index_hash*clientid_index_hash用于保存一个hash表,该hash表可通过客户端的ID快速找到该客户端在数组contexts中的索引;结构体成员struct mqtt3_config*config用于保存mosquitto的所有配置信息;
3)struct_mosquitto_subhier
数据结构struct _mosquitto_subhier是用于保存订阅树的节点(包括叶子节点和中间节点),mosquitto中对订阅树采用孩子-兄弟链表法的方式进行存储,该存储方式主要借助与数据结构struct _mosquitto_subhier来完成,该数据结构的定义为:
struct _mosquitto_subhier {
struct_mosquitto_subhier *children;
struct_mosquitto_subhier *next;
struct_mosquitto_subleaf *subs;
char*topic;
structmosquitto_msg_store *retained;
};
成员说明:
children :该成员指针指向同结构的第一个孩子节点;
next:该成员指针指向该节点的下一个兄弟节点;
subs:该成员指向订阅列表;
topic:该节点对应的topic片段;
3) struct _mosquitto_subleaf
在mosquitto程序中,对某一topic的所有订阅者被组织成一个订阅列表,该订阅列表是一个双向链表,链表的每个节点都保存有一个订阅者,该链表的节点即是:struct _mosquitto_subleaf,定义形式为:
struct _mosquitto_subleaf {
struct_mosquitto_subleaf *prev;
struct_mosquitto_subleaf *next;
structmosquitto *context;
int qos;
};
其中成员struct mosquitto *context表示一个订阅客户端,prev和next表示其前一个节点和后一个节点。
6)structmqtt3_config
结构体struct mqtt3_config用于保存mosquitto的所有配置信息,mosquitto程序在启动时将初始化该结构体并从配置文件中读取配置信息保存于该结构体变量内。
-
mosquitto源码分析(四)
2016-11-23 13:08:053.1.4、订阅树机制的优缺点分析 Mosquito程序采用订阅树形式维护客户端之间的订阅与发布消息,这种方式优点是逻辑清晰,便于开发和维护。缺点是其遍历过程效率较低。同时,程序中存在很多对订阅树的遍历过程:...本文由逍遥子撰写,转发请标注原址:
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完成。
图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所示:
图3-9 消息发布函数调用关系图
3.1.3、从订阅树中删除订阅客户端
在Mosquitto程序中,客户端可以向mosquitto服务器发送取消对某个topic的订阅请求,服务器收到请求之后,将从订阅树中删除该客户端,该过程需要遍历订阅树以找该topic在订阅树中的位置,进而获得到订阅该topic的订阅列表,从而将其从订阅树中删掉。该过程与发送消息类似,首先将topic进行分片,然后根据topic片段遍历订阅树找到该topic的订阅列表;然后遍历订阅列表,将该客户端从订阅列表中删除。
取消订阅的函数调用关系如图3-10所示。
图3-10 取消订阅函数调用关系
3.1.4、订阅树机制的优缺点分析
Mosquito程序采用订阅树形式维护客户端之间的订阅与发布消息,这种方式优点是逻辑清晰,便于开发和维护。缺点是其遍历过程效率较低。同时,程序中存在很多对订阅树的遍历过程:订阅、发布消息、取消订阅等,在客户端数量增加时,该功能对效率的影响将更为明显。
因此,在mosquitto的实际应用中很难支持5万以上的客户端,尤其在客户端网络状态不好时,其断开重练操作将非常频繁,这样也造成大量对订阅树的遍历操作,从而严重影响mosquitto的效率。
3.2、mosquitto的消息收发机制
Mosquito最主要的功能就是对消息的正确接收、维护和转发,因此其消息的接、收功能非常重要。Mosquitto的消息收发主要通过poll机制来完成。
-
Eclipse Mosquitto Mosquitto is an open source implementation of a server for version 5.0, 3.1.1, and 3.1 of the MQTT protocol. It also includes a C and C++ client library, and the mosquitto_pub and ...
-
转:mosquitto源码分析(一)
2017-04-27 18:13:00一、 Mosquitto简介 mosquitto是一款实现了消息推送协议MQTT v3.1 的开源消息代理软件,提供轻量级的,支持可发布/可订阅的的消息推送模式,使设备对设备之间的短消息通信变得简单,例如现在应用广泛的低功耗传感器... -
-
mosquitto源码分析(五)
2018-09-08 18:34:31原 mosquitto源码分析(五) ... -
Mosquitto源码分析及用go语言的重新实现(一、开篇)
2019-04-10 17:51:54Mosquitto简介: Mosquitto是用C语言实现的MQTT物联网协议v3.1 的消息代理服务器。...物联网最近乃至以后都会很火,业余时间计划对Mosquitto源码进行一个研究分析以及用go语言按着Mosquitto的思路去重... -
mosquitto源码分析(六)
2014-03-18 16:04:53Mosquitto代码的辅助功能主要包括:log输出功能、配置参数管理功能和内存封装的功能,这三个功能虽不是mosquitto的核心模块,但是却在其源码实现中经常遇到,它们的实现给mosquitto的代码开发带来了很大的方便。... -
mosquitto源码分析(三)
2018-09-08 18:56:40 本文由逍遥子撰写,转发请标注原址: http://write.blog.csdn.net/postedit/21462255 一、 Mosquito的核心功能分析 3.1、订阅树 Mosquitto通过订阅树的方式来管理... -
转:mosquitto源码分析(五)
2017-04-27 18:37:00本文由逍遥子撰写,转发请标注原址: ....NET /postedit/21464519 3.2.1、poll机制简介 ...Poll机制是一种I/O多路转接(I...此值需根据实际情况分析后确定。 转载于:https://www.cnblogs.com/killer-xc/p/6775714.html -
MQTT开源代理Mosquitto源码分析(访问控制篇)
2019-01-01 06:05:00对项目的工作流程有个大概理解是分析mosquitto的访问控制权限的基础,网络上已有很多中文博客在介绍,如逍遥子,尽管比较老,但是主要结构体的意义没有变;首先对结构体的含义有所理解对后面进一步看源码是非常有...