简介
MQTT是一个客户端服务端架构的发布/订阅模式的消息传输协议,它的设计思想是轻巧、开放、简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(M2M)以及物联网环境(IoT).
MQTT特性
MQTT在设计之初便确认了以下特性:
- 精简,功能和数据两个方面
- 发布/订阅模式,针对一对多
- 应对糟糕的网络环境
- 客户端计算能力较低
MQTT机制
订阅/发布机制
MQTT最重要的机制是订阅/发布机制,客户端连接 Broker 订阅 topic 来进行数据传输.
消息类型
MQTT协议包括14种不通的消息类型,可以通过报文中固定报文的第一个字节进行筛选.
遗愿机制
MQTT协议通过遗愿机制来应对糟糕的网络环境以及不稳定的客户端,当客户端与服务器出现故障时,服务端会根据上一条报文的遗愿消息进行发布,一般发布的条件包括且不限于:
- 服务端检测到了一个I/O错误或者网络故障
- 客户端在心跳时间(Keep Alive)内未能通信
- 客户端在未发送正常关闭(0x00)的情况下关闭了网络连接
- 服务端在没有收到正常关闭(0x00)的情况下关闭了网络链接
这样,当客户端故障的情况下,服务端可以进行后续处理,同时通知用户,而不需要长时间保持连接浪费系统资源.
心跳机制
-
心跳机制(Keep Alive)用双字节整数来表示以秒位单位的时间间隔. 它表示在客户端传输完成一个MQTT控制报文的时刻到下一个报文发送时刻所允许空闲的最大时间间隔.客户端负责保证两条报文之间的发送间隔不得超过心跳间隔.
-
如果没有信息需要发送, 至少且必须发送一个PINGREQ报文来通知服务端保持连接. 客户端可以随时发送PINGREQ报文, 并且可以使用PINGRESP报文判断网络和服务端的活动状态.
-
如果心跳间隔非零, 且服务端在1.5T的时间内没有收到客户端的控制报文, 则会关闭客户端的网络连接, 且判断网络连接以断开.
-
如果客户端发送了PINGREQ报文之后, 在一定时间内没有收到PINGRESP报文, 则客户端应该关闭到服务端的网络连接.
-
心跳间隔(Keep Alive)的值为零时,表示关闭心跳机制,客户端不必按特定时间发送MQTT控制报文.
消息质量(QoS)
消息质量同样是用来消息质量(QOS)分为三种等级:
- QOS=0,表示最多分发一次,不保证消息到达,可能会丢失或者重复,服务端不会返回确认消息
- QoS=1,表示至少分发一次,保证消息到达,但是可能会有重复,服务端需要返回确认消息PUBACK
- QoS=2,只分发一次,保证消息到达并且只有一次
MQTT协议内容
详细协议内容可参考 MQTT协议.
MQTT报文格式
MQTT报文由三部分组成:
- 固定报头(必需)
- 可变报头(可选)
- 有效载荷(可选)
固定报头
固定报头里包含当前报文的类型和报文长度:
位置 | 功能 |
---|---|
byte 1 | 报文类型+标志位 |
byte 2 | 剩余报文长度(可变) |
可变报头
可变报头包含报文标识符和属性.
报文标识符只存在于部分类型的MQTT报文中,占2个字节.
属性字段由属性长度和所有属性组成.
- 属性长度不包含自身长度,只是用于声明所有属性的长度,如果没有任何属性,则必须由属性长度位0的字段来指示.
- 属性由一段数据和一个定义了属性用途和数据类型的标识符组成.
有效载荷
一般为消息内容.每一种类型的报文都不一样,详见文档.
原因码
原因码是一个单字节无符号数,用来指示一次操作的结果. 小于0x80的原因码表示操作成功,大于等于0x80的原因码表示操作失败.
常用客户端
MQTT是多并发高连接数的一种通信协议, 常用的有:
- Mosquitto (C/C++)
- VerneMQ (ERLANG)
- EMQTT(ERLANG)
- ActiveMQ(Java)
- Mosca(Node.js)
Mosquitto
官方下载mosquitto可以直接进行测试,在配置文件中有详细配置,另外有库文件paho可以直接进行二次开发,里面有详细例程.
具体测试等有想搞得东西在搞…反正测试的也都差不多了…
EMQTT
EMQTT是国产的开源代码,用的erlang/otp写的,服务端可以直接下载使用,详细教程网上很多.
MQTT的协议格式都是标准的, 客户端语言支持多种语言.
MQTT应用的一些细节
流量相关
MQTT相对于其他的HTTP/TCP之类的来说流量的开销是最小的
tls加密会在设备和平台每次发包前加大概30字节的数据(应该是证书,具体没去确认)
keepalive的过程分为三个过程,会发三个数据包,大小大约是 54 54 60字节,如果启用了tls加密 就是84 84 60这样
mqtt的流量消耗的大体概念是 mqtt平台和设备只建立连接,5分钟的保活间隔,那么一个月大概会走6/8Mb的流量(后面是tls的数据)