MQTT 通信协议学习分享
-
前面的一些故事
在项目组任务中初次接触到了MQTT的通信协议,觉得非常新鲜有趣,在次做一些分享。其实这个任务早已完成,彼时只是接触了这个模型,但并未接触到实际的应用(典型的传统的用法就不说了),很难想到一个成熟应用模型(商业协议)。最近有公司客户提出mqtt协议的要求,并给了协议文档,于是在此做一个商业模型的分享,作为学习资料。
MQTT 是物联网众多通信协议里比较著名的一个,现在物联网云平台都提供MQTT的服务,比如阿里云、百度云等,这个协议适用于网络条件不那么稳定的场景,贴切于物联网的应用场景,它是基于订阅和发布的模型,这一点和其他的通信模型有很大不同,这也是它的特点和优势所在,此外它的有效负荷可以非常大,头部的耗费极低。下面将会做一些资料的索引和解析,想详细地讲一讲这个协议,篇幅会较长,会断断续续更下去,不便之处望谅解~
什么是MQTT?
Message Queuing Telemetry Transport,消息队列遥测传输
发展起源
MQTT 最初由 IBM 于上世纪 90 年代晚期发明和开发。它最初的用途是将石油管道上的传感器与卫星相连接。
它是一种支持在各方之间异步通信的消息协议。异步消息协议在空间和时间上将消息发送者与接收者分离,因此可以在不可靠的网络环境中进行扩展。使用了一个发布和订阅的模型。简要
MQTT是一个客户端服务端架构的发布/订阅模式的消息传输协议。它的设计思想是轻巧、开放、简单、规范,因此易于实现。这些特点使得它对很多场景来说都是很好的选择,包括受限的环境如机器与机器的通信(M2M)以及物联网环境(IoT),这些场景要求很小的代码封装或者网络带宽非常昂贵。
此协议运行在TCP/IP,或其它提供了有序、可靠、双向连接的网络连接上。它有以下特点:
-
使用发布/订阅消息模式,提供了一对多的消息分发和应用之间的解耦。
-
消息传输不需要知道负载内容。
-
提供三种等级的服务质量:.
- “最多一次”,尽操作环境所能提供的最大努力分发消息。消息可能会丢失。例如,这个等级可用于环境传感器数据,单次的数据丢失没关系,因为不久之后会再次发送。
- “至少一次”,保证消息可以到达,但是可能会重复。
- “仅一次”,保证消息只到达一次。例如,这个等级可用在一个计费系统中,这里如果消息重复或丢失会导致不正确的收费。
很小的传输消耗和协议数据交换,最大限度减少网络流量
- 异常连接断开发生时,能通知到相关各方。
三个角色
- Publisher 发布者(client)
发布应用消息给其它相关的客户端 - Subscriber 订阅者 (client)
订阅以请求接受相关的应用消息,退订以移除接受应用消息的请求 - Broker 代理服务器 (server)
接受来自客户端的网络连接
接受客户端发布的应用消息
处理客户端的订阅和取消订阅请求
转发应用消息给符合条件的已订阅客户端
(发布者和订阅者并不冲突,即对同一客户端发布和订阅可同时存在)
两个主要业务
- 发布和订阅
发布的内容包括主题名(Topic)和消息(message),订阅指定的主题(Topic)即可
三种服务质量(Quality of Service)
-
QoS_0
“至多一次”,消息发布完全依赖底层TCP/IP网络,会发生消息丢失或重复。如传感器数据的频繁上报。
-
QoS_1
“至少一次”,确保消息到达,但消息重复可能会发生。客户端应具有处理重复消息的能力。
-
QoS_2
“只有一次”,确保消息准确到达一次。应考虑时效性和资源代价。如计费系统、即时通讯类的APP的推送。
详解三种服务质量
-
QoS_0
-
此处应有文字详解
-
QoS_1
-
此处应有文字详解
-
QoS_2
-
此处应有文字详解
-
Message ID 和 QoS 降级
-
此处应有文字详解
MQTT 通信建立
- 稳定的socket连接
- 请求连接到服务器(登陆服务器)
- 发布、订阅、退订
- 心跳
MQTT 数据包结构
- 固定头(Fixed header)
2~5 byte, 存在于所有MQTT数据包中,表示数据包类型 - 可变头(Variable header)
存在于部分MQTT数据包中,数据包类型决定了可变头是否存在及其具体内容 - 消息体(Payload)
存在于部分MQTT数据包中,表示客户端收到的具体内容, 最大(< 268,435,455 byte)
MQTT连接及其遗嘱
-
“固定头”: 0X10
-
“可变头”:协议名(UTF-8编码)+协议版本1字节+连接的标识符1字节+心跳包时间2字节
-
“有效内容”: “用户ID” + “临终消息主题” + “临终消息” + “用户名” + “密码”
-
Will Retain:遗嘱保留到服务器,当有新的订阅者出现时,推送该条遗嘱
-
Clean Session:清除会话,当该客户端重新上线时是否继续已有的会话,包括所有订阅的主题
-
当客户端向服务端发送 DISCONNECT包时,其遗嘱将被丢弃
MQTT 订阅
-
“固定头”: 0X80
-
“可变头”:Message ID
-
“有效内容”: “消息主题” + “消息”
-
单个订阅包最多一次订阅8个主题
-
主题树,主题层级分隔符,单/多层分配符,‘/’,‘+’,‘#’,a+(a#)不允许,a/+/b(a/#/b)不允许
-
大小写敏感
-
同主题覆盖,与这个主题过滤器匹配的任何现存的保留消息必须被重发
MQTT 发布
-
“固定头”: 0X11
-
“可变头”:Message ID
-
“有效内容”: “消息主题” + “消息”
-
DUP:该条publish是否是重发的
-
RETAIN:消息保留到服务器,当有新的订阅者出现时,推送该条消息
-
一次只能发布一个消息
-
Broker为每个主题保留有且只有一条保留消息;
-
当要清除保留消息时可用同主题空的消息清除,服务端不能存储零字节的保留消息 ,此时在线的客户端将收到该主题的这条消息
-
发布主题不能包含通配符
MQTT的一个商用模型
待续
-
-
补上一个很棒的参考文字资料,做mqtt的开发和学习都是非常非常合适的!
https://github.com/Belief997/mqtt
-
MQTT的一个商用模型
后来发现这个这个用法亮点不在与mqtt的通信,但还是做个分享作为参考。
简单选取其中的MQTT部分来说- 在上下行消息方面,下行topic与设备的唯一动态操作序列号绑定,上行消息与设备 imei 号绑定。
- 在内容格式上,选用经典的 json 格式,内嵌对内容做指定格式的拼接源串做 MD5 之类的签名用作校验