MQTT
mqtt的工作原理 :
发布者发布主题会传到服务器, 由服务器下发到订阅该主题的订阅者.并非发布者和订阅者直接对接.
MQTT协议特点
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。
MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。
发布和订阅
MQTT使用的发布/订阅消息模式,它提供了一对多的消息分发机制,从而实现与应用程序的解耦。
这是一种消息传递模式,消息不是直接从发送器发送到接收器(即点对点),而是由MQTT server
(或称为 MQTT Broker)分发的。

MQTT 服务器是发布-订阅架构的核心。
客户端可以发布消息(发送方)、订阅消息(接收方)或两者兼而有之。
客户端(也称为节点)是一种智能设备,如微控制器或具有 TCP/IP 堆栈和实现 MQTT 协议的软件的计算机。
消息在允许过滤的主题下发布。主题是分层划分的 UTF-8 字符串。不同的主题级别用斜杠/
作为分隔符号。
我们来看看下面的设置。
光伏发电站是发布者(Publisher)。
主要主题(Topic)级别是”PV”,这个工厂发布两个子级别”sunshine”和”data”;
“PV/sunshine”是一个布尔值(true/false,也可以是 1/0),充电站需要它来知道是否应该装载电动汽车(仅在阳光普照时 :))。
充电站(EVSE)是订阅者,订阅”PV/sunshine”从服务器获取信息。
“PV/data” 另一方面,以 kW 为单位传输工厂产生的瞬时功率,并且该主题可以例如通过计算机或平板电脑订阅,以生成一天内传输功率的图表。
这就是一个简单的MQTT的应用场景,具体如下图所示:

QOS
服务质量是 MQTT 的一个重要特性。当我们使用 TCP/IP 时,连接已经在一定程度上受到保护。但是在无线网络中,中断和干扰很频繁,MQTT 在这里帮助避免信息丢失及其服务质量水平。这些级别在发布时使用。如果客户端发布到 MQTT 服务器,则客户端将是发送者,MQTT 服务器将是接收者。当MQTT服务器向客户端发布消息时,服务器是发送者,客户端是接收者。
QoS 0
这一级别会发生消息丢失或重复,消息发布依赖于底层TCP/IP网络。
至多一次(qos = 0),可能会出现丢包的现象。使用在对实时性要求不高的情况。这一级别可应用于如下情景,如环境传感器数据,丢失一次读记录无所谓,因为很快下一次读记录就会产生。
QoS 1
QoS 1 承诺消息将至少传送一次给订阅者。
至少一次(qos = 1),保证包会到达目的地,但是可能出现重包。
QoS 2
使用 QoS 2,我们保证消息仅传送到目的地一次。为此,带有唯一消息 ID 的消息会存储两次,首先来自发送者,然后是接收者。QoS 级别 2 在网络中具有最高的开销,因为在发送方和接收方之间需要两个流。
正好一次(qos = 2),保证包会到达目的地,且不会出现重包的现象。这一级别可用于如计费系统等场景,在计费系统中,消息丢失或重复可能会导致生成错误的费用。
MQTT数据包结构
固定头(Fixed header),存在于所有MQTT数据包中,表示数据包类型及数据包的分组类标识;
可变头(Variable header),存在于部分MQTT数据包中,数据包类型决定了可变头是否存在及其具体内容;
- 较常的应用是做为包的标识
消息体(Payload),存在于部分MQTT数据包中,表示客户端收到的具体内容;
- CONNECT、SUBSCRIBE、SUBACK、UNSUBSCRIBE四种类型的消息 有消息体:
CONNECT
,消息体内容主要是:客户端的ClientID、订阅的Topic、Message以及用户名和密码SUBSCRIBE
,消息体内容是一系列的要订阅的主题以及QoS
。SUBACK
,消息体内容是服务器对于SUBSCRIBE
所申请的主题及QoS
进行确认和回复。UNSUBSCRIBE
,消息体内容是要取消订阅的主题。
- CONNECT、SUBSCRIBE、SUBACK、UNSUBSCRIBE四种类型的消息 有消息体:
使用MQTT进行交互
当应用数据通过MQTT网络发送时,MQTT会把与之相关的服务质量(QoS)和主题名(Topic)相关连。
在MQTT客户端上干什么?
- 发布其他客户端会订阅的信息
- 订阅其它客户端发布的消息
- 退订或删除应用程序的消息
- 断开与服务器连接。
MQTT服务器又干什么?
- 接受来自客户的网络连接
- 向订阅的客户转发应用程序消息
MQTT协议中的方法
- (1)Connect。等待与服务器建立连接。
- (2)Disconnect。等待MQTT客户端完成所做的工作,并与服务器断开TCP/IP会话。
- (3)Subscribe。等待完成订阅。
- (4)UnSubscribe。等待服务器取消客户端的一个或多个topics订阅。
- (5)Publish。MQTT客户端发送消息请求,发送完成后返回应用程序线程。
MQTT如何实现订阅-发布消息模型?
MQTT如何管理连接?
MQTT 是工作在TCP / TLS 协议之上的,是基于连接的,因此在进行主题订阅或消息发布之前,需要先建立连接。MQTT Broker 为了保证网络安全,一般会对请求连接的Client 进行身份验证,因此CONNECT 报文可以携带身份验证信息。MQTT Client 与MQTT Broker 建立连接的过程如下:

MQTT如何传递消息?
MQTT 传递消息是基于订阅-发布模型的,Client 与Broker 建立连接后,如果想接收消息,需要先订阅自己感兴趣的主题topic,一个Client 可以订阅多个主题topic。MQTT Client 如果想对外发布消息,消息都需要指定主题topic,Broker 需要通过topic 确定要将该消息分发给哪些Client(MQTT Broker 为每个topic 维护一个订阅者列表)。MQTT Client 向Broker 订阅感兴趣主题topic 的过程如下:

MQTT 为了适应多种应用场景,支持不同的消息传递服务等级QoS,有些不重要的消息即便对方没有收到也影响不大,有些重要的消息则需要确认对方接收到了。还有些特殊场景,比如支付场景,不仅要求对方确认收到该消息,而且要求该消息的传递是幂等的,也即相同的消息发送多次跟发送一次是一样的结果,不至于出现重复支付的情况。
MQTT Client 取消订阅不感兴趣的主题时,通过UNSUBSCRIBE 报文告知Broker 要取消订阅哪些主题,报文中比较常用的参数是topic。Broker 也会通过UNSUBACK 报文通知Client 取消订阅主题的结果,报文中比较常用的参数是Reason Code。取消订阅的过程和报文格式跟订阅过程类似,这里就不赘述了。
MQTT Client 订阅感兴趣的主题后,如果其它Client 在该topic 上发布消息时,Broker 就可以将该主题上的消息转发给它的订阅者。MQTT Client 在指定主题上发布消息的过程如下:

前面介绍MQTT Client 订阅主题时也指定了QoS,Broker 实际发送给订阅者的消息服务等级还要看消息发布者将消息发送给Broker 的服务等级。也即,Publisher 到Subscribers 传递消息的服务等级等于发布报文中的QoS 和订阅报文中QoS 的最小值。
某个主题的消息从Publisher 经Broker 到Subscribers,采用不同的消息QoS 服务等级,传递消息的报文交互也不同,MQTT 支持的三种QoS 服务等级下,报文的交互过程对比如下:
- QoS 0 (At most once):Publisher / Broker 只管发布消息,不关心对方是否收到(类似于UDP 协议,没有确认重传机制),QoS 0 的消息发送速率比较高,但消息可能会丢失。常用于对消息丢失不敏感的场景,比如传感器发布状态数据,中间几次数据丢失没关系;
- QoS 1 (At least once):Publisher / Broker 通过PUBACK 报文确认对方收到了发布的消息,若一段时间内未收到对方的PUBACK 报文则继续重发该消息(重发的消息DUP 标识位设置为1,Packet Identifier 字段值不变),QoS 0 的消息保证对方接收到,但消息可能会重复(Broker / Subscribers 发送PUBACK 报文后再收到相同Packet Identifier 的消息也是按新消息处理的),比如下发给执行器的命令,需要确认命令被响应了;
- QoS 2 (Exactly once):Publisher / Broker 不仅要通过PUBREC 报文确认对方接收到了发布的消息,还要通过报文PUBREL 和PUBCOMP 的二次交互保证对方接收的消息不重复。这要求接收者Broker / Subscribers 先暂存该消息,等接收到了PUBREL 报文后再将消息递交给上层或转发(消息接收者会忽略PUBLISH 报文中相同Packet Identifier 的消息),QoS 0 的消息对硬件计算存储资源的要求较高、消息延迟也较高,比如在计费支付系统中,每笔订单需要且只能处理一次。

PUBREC字面意思为Assured publish received,作为订阅者/服务器对QoS level = 2的发布PUBLISH消息的发送方的响应,确认已经收到,为QoS level = 2消息流的第二个消息。 和PUBACK相比,除了消息类型不同外,其它都是一样。
PUBREL Qos level = 2的协议流的第三个消息,有PUBLISH消息的发布者发送,参与方接收。
PUBCOMP 作为QoS level = 2消息流第四个,也是最后一个消息,由收到PUBREL的一方向另一方做出的响应消息。完整的消息一览,和PUBREL一致,除了消息类型。
消息接收者Broker / Subscribers 在接收QoS 等级大于0(也即QoS 1 或QoS 2)的消息时,需要在本地暂存该消息(QoS 0 的消息本地不暂存,直接转发或递交给上层应用),QoS 1 的消息需要在本地存储到发送PUBACK 报文后,QoS 2 的消息需要在本地存储到接收PUBREL 报文后。
总结
这只是MQTT的基本理论知识,而更深层的理解需要不断实践。