物联网 (IoT) 设备必须连接互联网。通过连接到互联网,设备就能相互协作,以及与后端服务协同工作。互联网的基础网络协议是 TCP/IP。MQTT(消息队列遥测传输) 是基于 TCP/IP 协议栈而构建的,已成为 IoT 通信的标准。
MQTT 最初由 IBM 于上世纪 90 年代晚期发明和开发。它最初的用途是将石油管道上的传感器与卫星相链接。顾名思义,它是一种支持在各方之间异步通信的消息协议。异步消息协议在空间和时间上将消息发送者与接收者分离,因此可以在不可靠的网络环境中进行扩展。虽然叫做消息队列遥测传输,但它与消息队列毫无关系,而是使用了一个发布和订阅的模型。在 2014 年末,它正式成为了一种 OASIS 开放标准,而且在一些流行的编程语言中受到支持(通过使用多种开源实现)。
为何选择 MQTT
MQTT 是一种轻量级的、灵活的网络协议,致力于为 IoT 开发人员实现适当的平衡:
1、这个轻量级协议可在严重受限的设备硬件和高延迟/带宽有限的网络上实现。
2、它的灵活性使得为 IoT 设备和服务的多样化应用场景提供支持成为可能。
为了了解为什么 MQTT 如此适合 IoT 开发人员,我们首先来分析一下为什么其他流行网络协议未在 IoT 中得到成功应用。
为什么不选择HTTP
大多数开发人员已经熟悉 HTTP Web 服务。那么为什么不让 IoT 设备连接到 Web 服务?设备可采用 HTTP 请求的形式发送其数据,并采用 HTTP 响应的形式从系统接收更新。这种请求和响应模式存在一些严重的局限性:
1、HTTP 是一种同步协议。客户端需要等待服务器响应。Web 浏览器具有这样的要求,但它的代价是牺牲了可伸缩性。在 IoT 领域,大量设备以及很可能不可靠或高延迟的网络使得同步通信成为问题。异步消息协议更适合 IoT 应用程序。传感器发送读数,让网络确定将其传送到目标设备和服务的最佳路线和时间。
2、HTTP 是单向的。客户端必须发起连接。在 IoT 应用程序中,设备或传感器通常是客户端,这意味着它们无法被动地接收来自网络的命令。
3、HTTP 是一种 1-1 协议。客户端发出请求,服务器进行响应。将消息传送到网络上的所有设备上,不但很困难,而且成本很高,而这是 IoT 应用程序中的一种常见使用情况。
4、HTTP 是一种有许多标头和规则的重量级协议。它不适合受限的网络。
HTTP协议的两个过程,Request和Response,两个都有各自的语言格式,我们看下是什么。
请求报文格式:(注意这里有个换行)
<method> <request-URL> <version>
<headers>
<entity-body>
响应报文格式:(注意这里有个换行)
<version> <status> <reason-phrase>
<headers>
<entity-body>
方法method:
这个很重要,比如说GET和POST方法,这两个是很常用的,GET就是获取什么内容,而POST就是向服务器发送什么数据。当然还有其他的,比如HTTP 1.1中还有:DELETE、PUT、CONNECT、HEAD、OPTIONS、TRACE等一共8个方法(HTTP Method历史:HTTP 0.9 只有GET方法;HTTP 1.0 有GET、POST、HEAD三个方法)。
请求URL:
这里填写的URL是不包含IP地址或者域名的,是主机本地文件对应的目录地址,所以我们一般看到的就是“/”。
版本version:
格式是HTTP/<major>.<minor>这样的格式,比如说HTTP/1.1.这个版本代表的就是我们使用的HTTP协议的版本,现在使用的一般是HTTP/1.1
状态码status:
状态码是三个数字,代表的是请求过程中所发生的情况,比如说200代表的是成功,404代表的是找不到文件。
原因短语reason-phrase:
是状态码的可读版本,状态码就是一个数字,如果你事先不知道这个数字什么意思,可以先查看一下原因短语。
首部header:
注意这里的header我们不是叫做头,而是叫做首部。可能有零个首部也可能有多个首部,每个首部包含一个名字后面跟着一个冒号,然后是一个可选的空格,接着是一个值,然后换行。
实体的主体部分entity-body:
实体的主体部分包含一个任意数据组成的数据块,并不是所有的报文都包含实体的主体部分,有时候只是一个空行加换行就结束了。
下面我们举个简单的例子:
请求报文:
GET /index.html HTTP/1.1
Accept: text/*
Host: www.myweb.com
响应报文:
HTTP/1.1 200 OK
Content-type: text/plain
Content-length: 3
出于上述原因,大部分高性能、可扩展的系统都使用异步消息总线来进行内部数据交换,而不使用 Web 服务。事实上,企业中间件系统中使用的最流行的消息协议被称为 AMQP(高级消息排队协议)。但是,在高性能环境中,计算能力和网络延迟通常不是问题。AMQP 致力于在企业应用程序中实现可靠性和互操作性。它拥有庞大的特性集,但不适合资源受限的 IoT 应用程序。
除了 AMQP 之外,还有其他流行的消息协议。例如,XMPP(Extensible Messaging and Presence Protocol,可扩展消息和状态协议)是一种对等即时消息 (IM) 协议。它高度依赖于支持 IM 用例的特性,比如存在状态和介质连接。与 MQTT 相比,它在设备和网络上需要的资源都要多得多。
那么,MQTT 为什么如此轻量且灵活?MQTT 协议的一个关键特性是发布和订阅模型。与所有消息协议一样,它将数据的发布者与使用者分离。
它具有以下主要的几项特性:
1、使用发布/订阅消息模式,提供一对多的消息发布和应用程序之间的解耦;
2、消息传输不需要知道负载内容;
3、使用 TCP/IP 提供网络连接;
4、有三种消息发布的服务质量:
QoS 0:“最多一次”,消息发布完全依赖底层 TCP/IP 网络。分发的消息可能丢失或重复。例如,这个等级可用于环境传感器数据,单次的数据丢失没关系,因为不久后还会有第二次发送。
QoS 1:“至少一次”,确保消息可以到达,但消息可能会重复。
QoS 2:“只有一次”,确保消息只到达一次。例如,这个等级可用在一个计费系统中,这里如果消息重复或丢失会导致不正确的收费。
5、小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量;
6、使用 Last Will 和 Testament 特性通知有关各方客户端异常中断的机制;在MQTT协议中,一个MQTT数据包由:固定头(Fixed header)、 可变头(Variable header)、 消息体(payload)三部分构成。MQTT的传输格式非常精小,最小的数据包只有2个bit,且无应用消息头。
发布和订阅模型
MQTT 协议在网络中定义了两种实体类型:一个消息代理和一些客户端。代理是一个服务器,它从客户端接收所有消息,然后将这些消息路由到相关的目标客户端。客户端是能够与代理交互来发送和接收消息的任何事物。客户端可以是现场的 IoT 传感器,或者是数据中心内处理 IoT 数据的应用程序。
1、客户端连接到代理。它可以订阅代理中的任何消息 “主题”。此连接可以是简单的 TCP/IP 连接,也可以是用于发送敏感消息的加密 TLS 连接。
2、客户端通过将消息和主题发送给代理,发布某个主题范围内的消息。
3、代理然后将消息转发给所有订阅该主题的客户端。
因为 MQTT 消息是按主题进行组织的,所以应用程序开发人员能灵活地指定某些客户端只能与某些消息交互。例如,传感器将在 “sensor_data” 主题范围内发布读数,并订阅 “config_change” 主题。将传感器数据保存到后端数据库中的数据处理应用程序会订阅 “sensor_data” 主题。管理控制台应用程序能接收系统管理员的命令来调整传感器的配置,比如灵敏度和采样频率,并将这些更改发布到 “config_change” 主题。
IoT 传感器的 MQTT 发布和订阅模型
同时,MQTT 是轻量级的。它有一个用来指定消息类型的简单标头,有一个基于文本的主题,还有一个任意的二进制有效负载。应用程序可对有效负载采用任何数据格式,比如 JSON、XML、加密二进制或 Base64,只要目标客户端能够解析该有效负载。
MQTT 开发入门
下面我们介绍一下如何利用北京奇迹物联的AM20E模组实现MQTT协议接入阿里IoT平台。AM20E 是一款超小封装 NB-IoT 工业级无线通讯模块。内置多种协议栈TCP/IP,HTTP,MQTT等,本文我们使用其MQTT协议接入阿里的IoT平台,实现数据的上下行。
注册阿里云物联网平台
注册阿里云https://account.aliyun.com
注意:需要注册后实名认证才可以进入“物联网平台”(更名前叫物联网开发套件),操作中有任何问题可以从阿里云的技术支持找到对应文档查看。
注册后选择物联网平台
在控制台后创建产品
点击创建产品
创建完成产品,点击查看
点击前往管理
点击添加设备
添加完成设备后,将此三个信息记录下来
在此界面,点击功能定义
在功能定义界面,新增功能
在消息通信界面,查看Topic,这些Topic我们后期调试会用到
暂时用到的两个Topic,为
/sys/a1cn4I14cE9/${deviceName}/thing/event/property/post 设备属性上报
/sys/a1cn4I14cE9/${deviceName}/thing/service/property/set 设备属性设置
经过上面的准备,可以开始调试AM20E与在阿里云建立的设备上传下发数据了。
AM20E连接阿里云
阿里云建立的设备信息:
product_key: a1cn4I14cE9
device_name: AM20E00101
device_secret: xL7bM8oKmfOnM6wk9bwNsylJSOQW9kDD
连接流程如下:
AT+CSQ
+CSQ: 31,99
OK
AT+CPIN?
+CPIN:READY
OK
AT+CREG?
+CREG: 0,1
OK
AT+XIIC=1
OK
AT+IMQTTAUTH="a1cn4I14cE9","AM20E00101","xL7bM8oKmfOnM6wk9bwNsylJSOQW9kDD"
OK //发送鉴权信息
AT+IMQTTPARA="TIMEOUT",2 //设置参数
OK
+IMQTTAUTH:OK
AT+IMQTTCONN //连接
OK
AT+IMQTTSUB="/sys/a1cn4I14cE9/AM20E00101/thing/event/property/post",2
+IMQTTSUB:1
OK
+IMQTTSUB:1,2 //订阅一个topic
AT+IMQTTPUBS="/sys/a1cn4I14cE9/AM20E00101/thing/event/property/post",1,"{\"id\":\"789\",\"version\":\"1.0\",\"params\":{\"PM25\":25},\"method\":\"thing.event.property.post\"}"
+IMQTTPUB:2
OK
+IMQTTPUB:2,0
+IMQTTRCVPUB:46438,/sys/a1cn4I14cE9/AM20E00101/thing/event/property/post,86,{"id":"789","version":"1.0","params":{"PM25":25},"method":"thing.event.property.post"} //发送数据
AT+IMQTTSUB="/a1cn4I14cE9/AM20E00101/user/get",2
+IMQTTSUB:3
OK
+IMQTTSUB:3,2 //订阅下行的topic,并通过该topic下发数据
+IMQTTRCVPUB:0,/a1cn4I14cE9/AM20E00101/user/get,6,123456 //收到的数据
AT+IMQTTDISCONN //断开连接
OK
技巧和解决方法
MQTT 的优势在于它的简单性。在可以使用的主题类型或消息有效负载上没有任何限制。这支持一些有趣的用例。例如,请考虑以下问题:
如何使用 MQTT 发送 1-1 消息?双方可以协商使用一个特定于它们的主题。例如,主题名称可以包含两个客户端的 ID,以确保它的唯一性。
客户端如何传输它的存在状态?系统可以为 “presence” 主题协商一个命名约定。例如,“presence/client-id” 主题可以拥有客户端的存在状态信息。当客户端建立连接时,将该消息被设置为 true,在断开连接时,该消息被设置为 false。客户端也可以将一条 last will 消息设置为 false,以便在连接丢失时设置该消息。代理可以保留该消息,让新客户端能够读取该主题并找到存在状态。
如何保护通信?客户端与代理的连接可以采用加密 TLS 连接,以保护传输中的数据。此外,因为 MQTT 协议对有效负载数据格式没有任何限制,所以系统可以协商一种加密方法和密钥更新机制。在这之后,有效负载中的所有内容可以是实际 JSON 或 XML 消息的加密二进制数据。
文章奖励内容:
本文Candy奖励:GSMA 2019 《eSIM在中国-未来之路》产业报告
获得方式:扫码关注,留言“eSIM在中国”
——end----