MQTT 学习笔记
MQTT特点
MQTT协议是为大量计算能力有限,且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议。
1、使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合
2、对负载内容屏蔽的消息传输。
3、使用TCP/IP提供网络连接:
主流的MQTT是基于TCP连接进行数据推送的,但是同样有基于UDP的版本,叫做MQTT-SN。这两种版本由于基于不同的连接方式,优缺点自然也就各有不同了
4、有三种消息发布服务质量:
[1] “至多一次”,消息发布完全依赖底层TCP/IP网络。会发生消息丢失或重复:
这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。这一种方式主要普通APP的推送,倘若你的智能设备在消息推送时未联网,推送过去没收到,再次联网也就收不到了。
[2] “至少一次”,确保消息到达,但消息重复可能会发生:
这一种方式比较鸡肋,在我的想象中没能想到这种质量的发送在常规的APP开发中有什么用处。
[3] “只有一次”,确保消息到达一次:
这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。这种最高质量的消息发布服务还可以用于即时通讯类的APP的推送,确保用户收到且只会收到一次。
5、小型传输,开销很小(固定长度的头部是2字节),协议交换最小化,以降低网络流量:
6、使用Last Will和Testament特性通知有关各方客户端异常中断的机制:
Last Will:即遗言机制,用于通知同一主题下的其他设备发送遗言的设备已经断开了连接。
Testament:遗嘱机制,功能类似于Last Will 。
由于MQTT 协议具有开放、简单、轻量、易于实
现等优点, 因此他特别适用于低带宽, 网络不稳定,
网络代价昂贵以及处理器和存储器资源有限的嵌入式
设备和移动终端上.
术语:
客户端(Client):
使用MQTT的程序或设备。客户端总是通过网络连接到服务端。它可以
- 发布应用消息给其它相关的客户端。.
- 订阅以请求接受相关的应用消息
- 取消订阅以移除接受应用消息的请求。
- 从服务端断开连接。
服务端(Server):
一个程序或设备,作为发送消息的客户端和请求订阅的客户端之间的中介。服务端
- 接受来自客户端的网络连接
- 接受客户端发布的应用消息
- 处理客户端的订阅和取消订阅请求
- 转发应用消息给符合条件的客户端订阅
订阅(Subscription):
订阅包含一个主题过滤器(Topic Filter)和一个最大的服务质量(QoS)等级。订阅与单个会话(Session)关联。会话可以包含多于一个的订阅。会话的每个订阅都有一个不同的主题过滤器。
主题名(Topic Name):
附加在应用消息上的一个标签,服务端已知且与订阅匹配。服务端发送应用消息的一个副本给每一个匹配的客户端订阅。
主题过滤器(Topic Filter:):
订阅中包含的一个表达式,用于表示相关的一个或多个主题。主题过滤器可以使用通配符。
会话(Session):
客户端和服务端之间的状态交互。一些会话持续时长与网络连接一样,另一些可以在客户端和服务端的多个连续网络连接间扩展。
控制报文(MQTT Control Packet):
通过网络连接发送的信息数据包。MQTT规范定义了十四种不同类型的控制报文,其中一个(PUBLISH报文)用于传输应用消息。
系统框架设计
整个服务器部分主要分成三个层次. 第一层是
MQTT 消息推送broker, 负责完成协议底层的网络通
信机制以及针对各种不同类型消息的收发机制; 第二
层由身份验证模块、ACL 控制模块、自动订阅模块、
话题统计模块以及状态监控模块组成, 是在底层通信
机制的基础上完善整个系统实际应用中所需的各项功
能; 第三层是数据存储层, 为第二层的各个模块提供
数据的支持, 用于各项数据的统计与交互. 整个系统
框架如图1 所示.
各模块的设计与实现
消息推送中间件
目前在各种平台上对于MQTT协议有许多不同的
实现, 这里所选择的Mosquitto 是一款开源的基于C实
现的MQTT server/broker, 比较完整的实现了MQTT
协议中要求的各项基本功能, 可以在Windows, Linux
以及其它类Unix 系统中编译运行.
数据存储层
在数据存储层中, 有的数据是需要经常读取的,
比如用户的名称、密码、ID 以及用户间的好友关系等;
有的数据是需要经常写入和修改的, 比如某些话题的
订阅数; 有的数据是不经常读取或写入的, 比如服务
器的运行状态. 为了提高效率, 对于需要经常读取或
写入的与用户相关的数据, 用Redis 数据库存储, 对于
不经常读取或写入的与服务器状态相关的数据, 用
MYSQL 数据库存储.
这里的Redis 是一个基于key-value 的开源no-sql
数据库, 它将数据缓存在内存中, 相对于传统的关系
型数据库来说, 性能上有很大提高, 特别适用于对访
问速度和并发性要求比较高的情况[6,7]. 同时Redis 也
支持数据的持久化, 并且支持list, set, hash 等多种不同
的数据结构. 在这里采用Redis 来存储每个用户的用
户名密码等相关信息和与话题有关的数量统计, 以处理大并发量下的用户访问请求.
密码验证模块
在客户端向服务器发起连接请求的时候, 服务器
必须对其进行密码验证, 以决定是否接受该连接请求,
验证过程如图2 所示.
为了增加数据库的安全性, 在用户注册时需要对其
密码加密后再将其密文存入数据库, 这样即使有人利用
非法手段侵入数据库, 也无法得到用户的真实密码. 在
这里采用的MD5 加密算法是一种散列加密算法[8], 任何
一个密码经过MD5 的HASH 散列计算之后将会产生一
个128bit 的序列. 但是缺点是两个相同的密码会产生相
同的散列, 为了弥补这个不足, 需要引入SALT 技术[9],
在用户注册时生成一个随机数据, 与用户密码一起进行
散列计算, 然后将得到的密文和SALT 值一起存入数据
库中, 这样就可以保证即使用户的密码相同, 只要随机
的SALT 值不同, 其密文就不相同.
在用户发起连接请求时, 将用户提交的密码明文
与数据库中的SALT 值一起进行散列计算, 将所得密文
与数据库中密文进行比对即可对用户密码进行验证.
ACL 控制模块
为了规范用户行为, 需要对其话题的订阅和发布
进行权限控制. ACL(Access Control List)又称为访问控
制列表, 是一种通过匹配关系对访问权限进行控制,
以加强系统安全性的技术[10,11].
ACL 表采用的格式为:
user <username>
[read/write] <topic>
或者
pattern [read/write] <topic>
第一种格式为特定用户的权限控制规则, 第二种
格式为所有用户的权限控制规则, read 表示具有订阅
的权限, write 表示具有发布的权限, topic 采用层级结
构组织, 检查的时候从左至右各层依次进行匹配.
ACL 表赋予用户应该具有的最小权限, 只要满足表中
的一项, 即表示验证通过.
为了满足移动社交网络中的应用需求, 需要引入
通配符来表示用户之间的关系, 在这里, 用%u 表示用
户自身的用户名, %c 表示用户自身的ID 号, %f 表示用
户的单向关注的关系, %F 表示用户互相关注的关系
(这里我们称之为好友), +表示话题中单层的通配, #表
示话题中若干层的通配, 一个典型的ACL 表项为:
pattern read user/%F/presence/+
该规则表示该用户对所有他的好友的presence 之
下的一级子话题具有订阅的权限.
自动订阅模块
在系统的实际应用中, 用户需要接收各种各样的
推送话题, 例如系统的广播通知、好友的上线提醒、好
友发送的即时消息等, 如果每次上线的时候都由客户
端来对这些话题进行订阅, 不但会影响客户端的性能,
还会占用移动终端的网络资源, 尤其是在用户关系复
杂, 需要订阅大量话题的时候. 因此, 服务器可以在用
户登录成功之后为用户自动订阅这些话题, 以减少网
络上的数据交互. 自动订阅模块流程如图3 所示.
自动订阅支持ACL 控制模块中提到的各项通配
符, 并且将%u 替换为自身用户名, %c 替换为自身ID,
含有%f 和%F 的表项会被通配为多个话题分别进行自
动订阅. 一个典型的自动订阅表项为:
user/%F/presence/+ 1
表示每个用户上线时都会自动订阅其好友的
presence之下一级的话题, QoS设为1, 中间以空格分隔.
话题统计模块
当大量用户在一段时间内同时订阅某一话题, 或
者向某一话题发布消息时, 意味着这个话题是当前用
户所关注的热点. 因此, 对话题的统计有助于分析用
户群体的行为方式以及当前社会生活中的热点时事,
对于发掘用户的潜在需求有重要的意义.
为了提高消息推动服务器的性能, 话题的统计数
据记录在redis 数据库中, 以topic-count 的形式存储,
当用户在统计的话题上进行订阅或者发布的时候, 服
务器调用Redis 的INCR 或DECR 命令对统计数据进
行更新.
状态监控模块
要确保服务器长时间稳定的运行, 需要定期对系
统运行的状态进行监控. 一方面要监控服务器本身的
系统信息, 如CPU 占用率、内存占用率、磁盘剩余空
间大小、网络流量等等, 这些数据在linux 环境下可以
通过解析/proc 下相关文件的内容来获取; 另一方面需
要监控消息推送服务的运行状况, 如活跃的用户数、
用户订阅话题的总数等. Mosquitto 提供了对这些信息
进行统计的机制, 所得的数据将由服务器以话题的形
式定期进行发布, 监控模块需要以客户的身份登录并
订阅相应话题以获取相关信息, 采集到的结果插入到
MYSQL 数据库中, 以供服务器进行性能分析以预警.
MQTT 学习笔记的更多相关文章
- MQTT学习笔记——Yeelink MQTT维修 采用mqtt.js和paho-mqtt
0 前言 2014年8月yeelink推出基于MQTT协议的开关类型设备控制API.相比于基于HTTP RESTful的轮训方式,通过订阅相关主题消息,能够远程控制类应用实时性更好. 本文使用 ...
- 【转载】MQTT学习笔记——MQTT协议体验 Mosquitto安装和使用
http://blog.csdn.net/xukai871105/article/details/39252653 0 前言 MQTT是IBM开发的一个即时通讯协议.MQTT是面向M2M和物联 ...
- MQTT学习笔记
因为工作需要,了解了一下MQTT.顺便记下来,现在还不会用. 一.概述 MQTT(Message Queuing Telemetyr Transport 消息队列遥测传输协议):基于发布/订阅(Pu ...
- 物联网学习笔记三:物联网网关协议比较:MQTT 和 Modbus
物联网学习笔记三:物联网网关协议比较:MQTT 和 Modbus 物联网 (IoT) 不只是新技术,还是与旧技术的集成,其关键在于通信.可用的通信方法各不相同,但是,各种不同的协议在将海量“事物”连接 ...
- Nodejs学习笔记(十六)--- Pomelo介绍&入门
目录 前言&介绍 安装Pomelo 创建项目并启动 创建项目 项目结构说明 启动 测试连接 聊天服务器 新建gate和chat服务器 配置master.json 配置servers.json ...
- Nodejs学习笔记(十六)—Pomelo介绍&入门
前言&介绍 Pomelo:一个快速.可扩展.Node.js分布式游戏服务器框架 从三四年前接触Node.js开始就接触到了Pomelo,从Pomelo最初的版本到现在,总的来说网易出品还算不错 ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
随机推荐
- Java学习笔记(14)
需求:一个银行账户5000块,两夫妻一个拿着存折,一个拿着卡,开始取钱比赛,每次只能取1000,要求不准出现线程安全问题 public class Demo10 { public static voi ...
- Ubuntu 16.04重启Nautilus
关闭: nautilus -q 启动: 不要在命令行启动,直接在Dash中找到“文件”,然后启动,这样就可以在后台直接运行.
- Unity-EasyTouch插件之One Finger
这节课,我们主要讲下单个手指的测试.比如单击啊,双击啊,拖动,单手滑动等. 单击: public class TouchTest : MonoBehaviour { // Subscribe to e ...
- kibana-sentinl-监控报警
kibana 安装 sentin 插件 ./bin/kibana-plugin install https://github.com/sirensolutions/sentinl/releases/d ...
- 创建maven web项目无法创建sec目录
创建maven web项目无法创建sec目录 解决方法:-DarchetypeCatalog=internal
- [置顶] (奇迹冬瓜)坦克大战[MFC框架]
经过二次整合 重新放出MFC框架下的坦克大战 采用小窗口 多线程 双缓冲 动画帧化 碰撞检测 接口封装 混音 事件延迟等 力求做到代码与美工的双向化 开场动画 界面一 界面二 游戏界面 结束动画 零积 ...
- 不要在基类析构函数中调用纯虚函数,否则运行时会报错“pure virtual method called”
如上. 这是因为:delete派生类对象时,先调用派生类的析构函数,然后再调用基类的析构函数:此时如果调用纯虚函数的话,派生类的对象已经被破坏了,所以会报错. http://www.cnblogs.c ...
- Solidworks如何让齿轮运动副保证持续啮合状态
出现这种情况一般是齿轮的比例有问题,如果你选择两个齿轮的齿顶圆的面,则自动比例是44:74,然后手动转动某个齿轮,就会出现不能啮合的情况 只要模数相同的齿轮不管大小都能始终啮合,但是你需要首先为每 ...
- 做一个创建cocos2d-x新项目的shell脚本
1. 进入console目录 cd /Users/apple/Documents/MyArchitecture/Cocos2d-x/Framework/cocos2d-x-3.4/tools/coco ...
- Android开发 之 我的jar包引用方法
1.在工程上名上右键->Build Path ->Configure Build Path 2.在Libraries选项卡中,选择右侧的Add External JARs,然后选择要导入的 ...