EMQTT入门

原文地址:http://dataguild.org/?p=6957

官网地址

emptt: https://developer.emqx.io/docs/broker/v3/cn/guide.html

paho: https://github.com/eclipse/paho.mqtt.python

MQTT英文文档:MQTT Version 3.1.1

MQTT文档中文翻译:Introduction · MQTT协议中文版

教程

  1. MQTT入门篇:https://link.zhihu.com/?target=http%3A//dataguild.org/%3Fp%3D6817
  2. MQTT进阶篇:https://link.zhihu.com/?target=http%3A//dataguild.org/%3Fp%3D6846
  3. MQTT安全篇:https://link.zhihu.com/?target=http%3A//dataguild.org/%3Fp%3D6866
  4. MQTT实战篇:https://link.zhihu.com/?target=http%3A//dataguild.org/%3Fp%3D6957

 

安装

环境:ubuntu18.04

emqx-ubuntu18.04-v3.2.1_amd64.deb 下载地址:https://github.com/emqx/emqx/releases

Python客户端:https://github.com/eclipse/paho.mqtt.python

常用命令

emqx start # 直接启动
sudo service emqx start # service 启动
sudo systemctl start emqx # systemctl 启动
emqx_ctl status

EMQ 管理控制台功能简介

如果 EMQ 安装在本机,则使用浏览器打开地址 http://127.0.0.1:18083 ,输入默认用户名 admin 与默认密码 public ,登录进入 Dashboard。如果忘记了管理控制台密码,使用 管理命令 重置或新建管理账号。

topic匹配规则基础

主题层级分隔符  / :     用于分割主题层级,/分割后的主题,这是消息主题层级设计中很重要的符号。

单层通配符  +:      单层通配符只能匹配一层主题。比如:   aaa/+     可以匹配 aaa/bbb ,但是不能匹配aaa/bbb/ccc。   单独的+号可以匹配单层的所有推送

多层通配符  #:   多层通配符可以匹配于多层主题。比如: aaa/#   不但可以匹配aaa/bbb,还可以匹配aaa/bbb/ccc/ddd。  也就是说,多层通配符可以匹配符合通配符之前主题层级的所有子集主题。单独的#匹配所有的消息主题.

简单的发布订阅示例

订阅者

import paho.mqtt.client as mqtt


def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))


def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))


client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("192.168.1.54", 1883, 600)
client.subscribe('emqtt', qos=0)
client.loop_forever()

发布者

import paho.mqtt.client as mqtt


def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))


def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))


client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("192.168.1.54", 1883, 600)
client.publish('emqtt', payload='Hello,EMQ!', qos=0)
client.loop_start()

发布者

import paho.mqtt.client as mqtt

HOST = "192.168.44.31"
PORT = 1883

def Publish_Message():
    client = mqtt.Client()
    client.username_pw_set(username='admin', password='public')  # 用于添加了插件认证方式后
    client.connect(HOST, PORT, 60)
    for x in range(10):
        Message = "hello" + str(x)
        client.publish("services", Message, 0)  # 发布一个主题为'services',内容为‘hello x’的信息
    # time.sleep(10)
    client.loop_forever()  # 保持连接状态

if __name__ == '__main__':
    Publish_Message()

发布者,主要内容:publish("topic_name","utf8_message",Qos)

  • Qos:0 --> 发送者只发送一次消息,不进行重试,Broker不会返回确认消息。Broker可能没有接收到消息。(默认)
  • Qos:1 --> 发送者最少发送一次消息,确保消息达到Broker,Broker需要返回确认消息PUBACK。Broker可能接收到重复消息。
  • Qos:2 --> 使用两阶段确认来保证消息的不丢失和不重复。Broker肯定会接收到消息,且只收到一次。

订阅者

import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))  # rc表示返回来的状态值
    client.subscribe("services")

def on_message(client, userdata, msg):
    print(msg.topic+" " + ":" + str(msg.payload))

if __name__ == "__main__":
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.username_pw_set(username='admin', password='public')  # 用于添加了插件认证方式后
    client.connect("192.168.44.31", 1883, 60)
    client.loop_forever()

订阅者,信息的产出在msg.payload

rc值代表的含义: 
0: Connection successful 
1: Connection refused - incorrect protocol version 
2: Connection refused - invalid client identifier 
3: Connection refused - server unavailable 
4: Connection refused - bad username or password 
5: Connection refused - not authorised 
6-255: Currently unused.


物联网(Internet of Things,IoT)最近曝光率越来越高。虽然HTTP是网页的事实标准,不过机器之间(Machine-to-Machine,M2M)的大规模沟通需要不同的模式:之前的请求/回答(Request/Response)模式不再合适,取而代之的是发布/订阅(Publish/Subscribe)模式。这就是轻量级、可扩展的MQTT(Message Queuing Telemetry Transport)可以施展拳脚的舞台。

MQTT简介

MQTT是基于二进制消息的发布/订阅编程模式的消息协议,最早由IBM提出的,如今已经成为OASIS规范。由于规范很简单,非常适合需要低功耗和网络带宽有限的IoT场景,比如:

  • 遥感数据
  • 汽车
  • 智能家居
  • 智慧城市
  • 医疗医护

由于物联网的环境是非常特别的,所以MQTT遵循以下设计原则:

  1. 精简,不添加可有可无的功能。
  2. 发布/订阅(Pub/Sub)模式,方便消息在传感器之间传递。
  3. 允许用户动态创建主题,零运维成本。
  4. 把传输量降到最低以提高传输效率。
  5. 把低带宽、高延迟、不稳定的网络等因素考虑在内。
  6. 支持连续的会话控制。
  7. 理解客户端计算能力可能很低。
  8. 提供服务质量管理。
  9. 假设数据不可知,不强求传输数据的类型与格式,保持灵活性。

运用MQTT协议,设备可以很方便地连接到物联网云服务,管理设备并处理数据,最后应用到各种业务场景,如下图所示:

发布/订阅模式

与请求/回答这种同步模式不同,发布/订阅模式解耦了发布消息的客户(发布者)与订阅消息的客户(订阅者)之间的关系,这意味着发布者和订阅者之间并不需要直接建立联系。打个比方,你打电话给朋友,一直要等到朋友接电话了才能够开始交流,是一个典型的同步请求/回答的场景;而给一个好友邮件列表发电子邮件就不一样,你发好电子邮件该干嘛干嘛,好友们到有空了去查看邮件就是了,是一个典型的异步发布/订阅的场景。

熟悉编程的同学一定非常熟悉这种设计模式了,因为它带来了这些好处:

  • 发布者与订阅者不必了解彼此,只要认识同一个消息代理即可。
  • 发布者和订阅者不需要交互,发布者无需等待订阅者确认而导致锁定。
  • 发布者和订阅者不需要同时在线,可以自由选择时间来消费消息。

主题

MQTT是通过主题对消息进行分类的,本质上就是一个UTF-8的字符串,不过可以通过反斜杠表示多个层级关系。主题并不需要创建,直接使用就是了。

主题还可以通过通配符进行过滤。其中,+可以过滤一个层级,而#只能出现在主题最后表示过滤任意级别的层级。

举个例子:

  • building-b/floor-5:代表B楼5层的设备。
  • +/floor-5:代表任何一个楼的5层的设备。
  • building-b/#:代表B楼所有的设备。

注意,MQTT允许使用通配符订阅主题,但是并不允许使用通配符广播。

服务质量

为了满足不同的场景,MQTT支持三种不同级别的服务质量(Quality of Service,QoS)为不同场景提供消息可靠性:

  • 级别0:尽力而为。消息发送者会想尽办法发送消息,但是遇到意外并不会重试。
  • 级别1:至少一次。消息接收者如果没有知会或者知会本身丢失,消息发送者会再次发送以保证消息接收者至少会收到一次,当然可能造成重复消息。
  • 级别2:恰好一次。保证这种语义肯定会减少并发或者增加延时,不过丢失或者重复消息是不可接受的时候,级别2是最合适的。

服务质量是个老话题了。级别2所提供的不重不丢很多情况下是最理想的,不过往返多次的确认一定对并发和延迟带来影响。级别1提供的至少一次语义在日志处理这种场景下是完全OK的,所以像Kafka这类的系统利用这一特点减少确认从而大大提高了并发。级别0适合鸡肋数据场景,食之无味弃之可惜,就这么着吧。

消息类型

MQTT拥有14种不同的消息类型:

  1. CONNECT:客户端连接到MQTT代理
  2. CONNACK:连接确认
  3. PUBLISH:新发布消息
  4. PUBACK:新发布消息确认,是QoS 1给PUBLISH消息的回复
  5. PUBREC:QoS 2消息流的第一部分,表示消息发布已记录
  6. PUBREL:QoS 2消息流的第二部分,表示消息发布已释放
  7. PUBCOMP:QoS 2消息流的第三部分,表示消息发布完成
  8. SUBSCRIBE:客户端订阅某个主题
  9. SUBACK:对于SUBSCRIBE消息的确认
  10. UNSUBSCRIBE:客户端终止订阅的消息
  11. UNSUBACK:对于UNSUBSCRIBE消息的确认
  12. PINGREQ:心跳
  13. PINGRESP:确认心跳
  14. DISCONNECT:客户端终止连接前优雅地通知MQTT代理

后面我们会给出具体的例子。

MQTT代理

市面上有相当多的高质量MQTT代理,其中mosquitto是一个开源的轻量级的C实现,完全兼容了MQTT 3.1和MQTT 3.1.1。下面我们就以mosquitto为例演示一下MQTT的使用。环境是百度开放云的云服务器以及Ubuntu 14.04.1 LTS,简单起见MQTT代理和客户端都安装在同一台云服务器上了。

首先SSH到云服务器,安装mosquitto以及搭配的客户端:

apt-get install mosquitto
apt-get install mosquitto-clients

现在在云端模拟云服务,订阅某办公楼5层的温度作为主题:

mosquitto_sub -d -t 'floor-5/temperature'
Received CONNACK
Received SUBACK
Subscribed (mid: 1): 0

然后另外打开一个SSH连接,模拟温度计发送温度消息:

mosquitto_pub -d -t 'floor-5/temperature' -m '15'
Received CONNACK
Sending PUBLISH (d0, q0, r0, m1, 'floor-5/temperature', ... (2 bytes))

此时回到第一个SSH客户端可以看到信息已经接收到了,之后便是心跳消息:

Received PUBLISH (d0, q0, r0, m0, 'floor-5/temperature', ... (2 bytes))
15
Sending PINGREQ
Received PINGRESP

需要注意的是mosquitto客户端默认使用QoS 0,下面我们使用QoS 2订阅这个主题:

mosquitto_sub -d -q 2 -t 'floor-5/temperature'
Received CONNACK
Received SUBACK
Subscribed (mid: 1): 2

切换到另外SSH连接然后在这个主题里面发送温度消息:

mosquitto_pub -d -q 2 -t 'floor-5/temperature' -m '15'
Received CONNACK
Sending PUBLISH (d0, q2, r0, m1, 'floor-5/temperature', ... (2 bytes))
Received PUBREC (Mid: 1)
Sending PUBREL (Mid: 1)
Received PUBCOMP (Mid: 1)

此时回到第一个SSH客户端可以看到信息已经接收到了,以及相应的多次握手消息:

Received PUBLISH (d0, q2, r0, m1, 'floor-5/temperature', ... (2 bytes))
Sending PUBREC (Mid: 1)
Received PUBREL (Mid: 1)
15
Sending PUBCOMP (Mid: 1)

至此我们初步了解了MQTT的基本知识,祝大家在物联网的世界里面玩得开心! 


WebSockets实现与HTTP网页交互 

MQTT是基于TCP协议实现,基于HTTP的网页应用便无法与之交互了。为了解决这个问题,许多MQTT代理加上了对WebSockets的支持,可以方便地实现如下场景:

  • 显示设备的实时信息
  • 接收报警等推送信息
  • 查看设备的历史消息

 

目前Ubuntu 14.04.1 LTS自带的Mosquitto版本比较低,所以我们将使用PPA上的新版本:

apt-add-repository ppa:mosquitto-dev/mosquitto-ppa
apt-get update
apt-get install mosquitto
apt-get install mosquitto-clients

 

以下实验是基于已经支持WebSockets的1.4.5版本的Mosquitto。打开WebSockets很简单,只需要在/etc/mosquitto/mosquitto.conf中添加:

listener 8001
protocol websockets

指定以上配置文件重启Mosquitto服务之后,便可以通过任意MQTT over WebSockets的界面,比如HiveMQ WebSockets Client Showcase或者MQTT Client Sample来把玩了:

浏览器其实是以WebSockets协议与MQTT代理交互的,不但可以完成mosquitto_pub和mosquitto_sub的功能,还可以结合HTML5的特性完成很多有意思的场景。下面我们就来实现温度感知器的图形界面。

下面是网页应用的源代码,其中用到了Paho JavaScript Client实现了MQTT over WebSockets:

<!DOCTYPE html>
<html>
  <head>
    <title>Start Page</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="mqttws31.js"></script>
  </head>
  <body>
    <label>当前温度</label>
    <meter max="100" low="60" high="80" value="30" id="meter"></meter>
 
    <script>
      var client = new Paho.MQTT.Client("host", 8001, "clientId");
 
      client.onMessageArrived = function (msg) {
        document.querySelector("#meter").value = msg.payloadString;
      };
 
      client.connect({
        onSuccess: function () {
          client.subscribe("floor-5/temperature");
        }
      });
    </script>
  </body>
</html>

代码非常直观,在连接到MQTT代理之后便订阅五楼温度的主题。当后台感知器发送温度信息后,比如用MQTT快速入门中提到的命令模拟:

mosquitto_pub -d -q 2 -t 'floor-5/temperature' -m '95'


 

MQTT安全篇

物联网的核心是连接万物,通过交换并分析数据使得生活更舒适与便捷。不过,敏感数据泄露或者设备被非法控制可不是闹着玩的。比如前段时间国内某著名家电企业的智能洗衣机,使用了某著名电商基于XMPP协议的物联网平台,不费吹灰之力便被黑客攻破并远程遥控,给智能家居的发展带来了一些阴影。究其本质,并不是物联网技术本身有缺陷,而是在物联网系统的设计中最基本的安全设计被工程师轻视了,才导致整个系统的崩塌。

在这里我们将介绍为何以及如何运用MQTT提供的安全特性来保证物联网项目的顺利实施。

安全对于几乎所有的项目都是一个挑战,对于物联网项目更是如此:

  • 设备安全性与设备可用性之间往往是零和博弈。
  • 加密算法需要更多的计算能力,而物联网设备的性能往往非常有限。
  • 物联网的网络条件常常要比家庭或者办公室的网络条件差许多。

对于以上挑战,MQTT提供了多个层次的安全特性:

  1. 网络层:有条件可以通过拉专线或者使用VPN来连接设备与MQTT代理,以提高网络传输的安全性。
  2. 传输层:传输层使用TLS加密是确保安全的一个好手段,可以防止中间人攻击(Man-In-The-Middle Attack)。客户端证书不但可以作为设备的身份凭证,还可以用来验证设备。
  3. 应用层:MQTT还提供客户标识(Client Identifier)以及用户名密码,在应用层验证设备。

虽然MQTT提供了多重安全设计,不过世界上并没有银弹能够保障数据的绝对安全,所以应该在设计的时候就把安全放在设计目标之中并拥有相当的优先级,否则上文提到的智能洗衣机就是一个活生生的教训。

网络层可以使用专线或者VPN超出了本文的范围,下面我们结合Mosquitto仔细了解一下传输层和应用层的MQTT安全特性。

加密

MQTT是基于TCP的,默认情况通讯并不加密。如果你需要传输敏感信息或者对设备进行反控,使用TLS几乎是必须的。打个比方,如果你在咖啡店用免费Wi-Fi上网,登录互联网金融的网站不支持HTTPS传输,那么你的账号信息多半已经在咖啡店的Wi-Fi日志里面躺着了……

TLS是非常成熟的安全协议,在握手的时候便可以创建安全连接,使得黑客无法窃听或者篡改内容了。使用TLS的时候有以下注意点:

  • 尽可能使用高版本的TLS。
  • 验证X509证书链防止中间人攻击。
  • 尽量使用有CA发布的证书。

当然,TLS会增加连接时开销,对低运算能力的设备而言是额外的负担,不过如果设备是长连接的话就会避免反复连接的开销。

Mosquitto原生支持了TLS加密,生成证书后再配置一下MQTT代理即可。

首先我们需要生成证书权威(Certificate Authority,CA)的认证和密钥,生成过程中Common Name一定要填写Fully Qualified Domain Name(测试起见用IP地址也凑合):

openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt

接下来生成MQTT代理使用的密钥:

openssl genrsa -des3 -out server.key 2048

并去除密码:

openssl genrsa -out server.key 2048

然后为MQTT代理准备一个认证注册请求(Certificate Signing Request,CSR),这里的Common Name也要写对:

openssl req -out server.csr -key server.key -new

最后通过CA签署这个CSR生成MQTT代理证书:

openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 

现在配置/etc/mosquitto/mosquitto.conf,确保8883端口的设置如下:

listener 8883
cafile /etc/mosquitto/tls/ca.crt
certfile /etc/mosquitto/tls/server.crt
keyfile /etc/mosquitto/tls/server.key

重启Mosquitto服务就可以用以下命令订阅和发布消息了,当然所有消息都由TLS加密,可以无忧无虑地传递私密信息啦:

mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt
mosquitto_pub -h host -p 8883 -t 'topic' -m '15' --cafile ca.crt

 

其中,host需要与前面指定的Common Name一致,否则TLS连接会报错,错误信息也不是很直观……

认证

认证是验证设备身份的过程。拿旅行做比方,在换登机牌的时候需要出示护照以验明正身,即使别人能够假冒你的名字,但是拿不出护照便无法伪造身份。买房的时候,需要通过户口本证明你妈是你妈。

MQTT支持两种层次的认证:

  • 传输层:传输层使用TLS不但可以加密通讯,还可以使用X509证书来认证设备。
  • 应用层:MQTT支持客户标识、用户名密码以及X509证书,在应用层验证设备。

通过传输层和应用层来解释认证并不直观,下面我们直接从客户标识、用户名密码以及X509证书的角度来了解认证。

客户标识

用户可以使用最多65535个字符作为客户标识(Client Identifier),UUID或者MAC地址最为常见。

使用客户标识来认证并不可靠,不过在某些封闭的环境中或许已经足够。

用户名密码

MQTT协议支持通过CONNECT消息的username和password字段发送用户名和密码。

用户名密码的认证使用起来非常方便,不过再强调一下,由于用户名密码是以明文形式传输,在通过互联网时使用TSL加密是必须的。

Mosquitto支持用户名/密码认证方式,只要确保/etc/mosquitto/mosquitto.conf有如下设置:

password_file /etc/mosquitto/passwd
allow_anonymous false 

其中passwd文件是用来保存用户名和密码的,可以通过mosquitto_passwd来维护用户名密码。之后便可以通过如下命令订阅和发布消息了:

mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt -u user -P pwd
mosquitto_pub -h host -p 8883 -t 'topic' -m '9' --cafile ca.crt -u user -P pwd

这里端口使用8883是假设已经配置了TLS加密的。

结合TLS加密的用户名密码认证,已经是相对完善的安全体系了。

X509证书

MQTT代理在TLS握手成功之后可以继续发送客户端的X509证书来认证设备,如果设备不合法便可以中断连接。

使用X509认证的好处,是在传输层就可以验证设备的合法性,在发送MQTT CONNECT之前便可以阻隔非法设备的连接,以节省后续不必要的资源浪费。

如果你可以控制设备的创建和设置,X509证书认证或许是个非常好的选择。不过代价也是有的:

  1. 需要设计证书创建流程。如果你对设备有着完全的控制,在设备出厂前就能烧录X509证书到设备中,那么这条路是非常合适的。但是,对于移动设备等无法实现烧录证书的场景,用户名/密码认证或许是更好的选择。
  2. 需要管理证书的生命周期,最好通过PKI(Public-Key-Infrastructure)来管理。
  3. 如果证书泄露了,一定要立即使证书失效。一个选择是使用证书黑名单(Certificate Revocation Lists),另一个选择是提供在线证书状态协议(Online Certificate Status Protocol),方便MQTT代理及时了解证书的状态。

MQTT原生支持X509认证,生成客户证书后再配置一下MQTT代理便可。

首先生成设备密钥:

openssl genrsa -des3 -out client.key 2048

然后为准备一个设备认证注册请求:

openssl req -out client.csr -key client.key -new

最后通过CA签署这个CSR生成设备证书:

openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365

现在配置/etc/mosquitto/mosquitto.conf,确保8883端口的设置如下:

listener 8883
cafile /etc/mosquitto/tls/ca.crt
certfile /etc/mosquitto/tls/server.crt
keyfile /etc/mosquitto/tls/server.key
require_certificate true

重启Mosquitto服务就可以用以下命令订阅和发布消息了,当然所有消息都由TLS加密,可以无忧无虑地传递私密信息啦:

mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt --cert client.crt --key client.key
mosquitto_pub -h host -p 8883 -t 'topic' -m '95' --cafile ca.crt --cert client.crt --key client.key

可以看到,X509同时提供了完善的加密和验证,只是证书的生命周期管理的代价要比用户名密码高一些。

授权

授权是对资源的访问权限。继续拿机场做例子,在使用护照认证了用户之后,系统会根据预定决定用户可以上特定时间和班次的飞机,这就是授权。

对MQTT而言意味着对主题的订阅和发布权限。Mosquitto内置了基本的授权,那就是基于Access Control List的授权。

由于ACL是基于特定用户的,所以需要使用用户名密码认证方式。然后,在/etc/mosquitto/mosquitto.conf中指定ACL文件:

acl_file /etc/mosquitto/acl

在这个ACL文件便可以指定用户的读写权限,比如下面便可以授权用户tom读写指定主题的权限:

user tom
topic readwrite company/building/floor/#

Mosquitto只提供了基本的基于ACL的授权,更高级的基于RBAC的授权可能需要通过插件的形式自行开发了。

体系

在MQTT项目实施时,还可以考虑通过防火墙保护MQTT代理:

  • 仅允许相关的流量传递到MQTT代理,比如UDP、ICMP等流量可以直接屏蔽掉。
  • 仅允许相关端口的流量传递到MQTT代理,比如MQTT over TCP使用1883,而MQTT over TLS使用8883。
  • 仅允许某些IP地址段来访问MQTT代理,如果业务场景允许的话。

篇幅有限,本文只涉及了MQTT安全体系设计的冰山一角,如果读者感兴趣还可以参考HiveMQ发布的Introducing the MQTT Security Fundamentals系列博文。堡垒往往最容易从内部攻破,只有在系统在设计的时候就把安全放在首要位置并且积极地去做威胁模型分析,这才能有效保护用户数据。


前几篇文章我们介绍了MQTT协议本身,虽然非常适合物联网项目,但是在项目实施的时候有诸多不便:mosquitto等开源产品可扩展性不佳、需要自己签发X509证书、认证与授权不灵活、MQTT服务需要自己运维等。所以,在实施物联网服务的时候,应该采用云端的托管服务,以便聚焦物联网业务,而不是为了基础架构和运维烦恼。

这次我们将通过百度开放云物联网服务IoT来体验一下云端的MQTT托管服务是一个什么样的体验。

背景

百度开放云物联网(IoT)服务是一个全托管的云服务,帮助建立设备与云端之间安全可靠的双向连接,以支撑各种类型的物联网项目,而无需考虑服务的运维。

使用物联网服务提供如下好处:

  1. 从设备到云端以及从云端到设备可靠地进行大规模消息传输。
  2. 对设备认证与权限管理,并保证数据安全传输。
  3. 支持多种语言开发,兼容主流硬件设备。
  4. 与大数据服务无缝对接,以数据分析驱动业务进步。

为了更好地支持设备与云端之间的互联互通,百度开放云物联网服务原生支持MQTT(Message Queuing Telemetry Transport)协议。MQTT是基于二进制消息的发布/订阅编程模式的消息协议,最早由IBM提出的,如今已经成为OASIS规范。与HTTP、CoAP、XMPP等协议相比,MQTT协议有以下的优势:

  • MQTT基于TCP,在反控设备的时候比CoAP等基于UDP的协议更可靠,比如使用3G通讯的时候需要专门实现CoAP over TCP,否则反控很不稳定。
  • MQTT异步Pub/Sub实现,好比发个短信,无需等待对方确认便可以继续,而不像HTTP、CoAP那样必须等待对方应答才能返回的同步模式。
  • MQTT为物联网提供了许多体贴的设计,比如QoS,比如“遗言”等设计。
  • MQTT是二进制格式,比XMPP更轻量级。

总之,通过支持轻量级可扩展的MQTT,百度开放云物联网服务非常适合需要低功耗和网络带宽有限的物联网场景,国外的公有云供应商如AWS、Azure、Bluemix等都以各种形式加入了对MQTT的支持。

使用物联网服务的参考架构如下:

 

为了保障安全,开放云物联网服务的MQTT通讯都是通过SSL加密的,确保消息不会被监听与篡改。

要使用百度物联网服务,请到这里申请测试。目前提供的是基于命令行的用户体验,可以参考入门指南配置Python环境并下载命令行工具。

运维体验

百度物联网服务分为运维人员体验和开发人员体验两部分。首先让我们来看运维人员体验。

首先需要创建IoT实例,以容纳多个设备、身份、策略等资源:

1
bce.py iot create-endpoint --endpoint-name "smart-project"

在实例下面可以创建一或多个设备:

1
bce.py iot create-thing --endpoint-name "smart-project" --thing-name "sensor-100"

成功创建设备后,系统返回username,是用来作为标识符与MQTT服务交互的。

下面进行权限管理,保证设备能够对特定的主题订阅发布消息。

首先需要创建一个或多个身份(Principal)来代表物联网服务中的认证主体。对于物联网服务,权限绑定在身份而不是设备上的,这样用户可以为每个设备创建不同的身份,或者设备共享一个身份,非常灵活:

1
bce.py iot create-principal --endpoint-name "smart-project" --principal-name "sensor-principle"

身份创建成功后,服务返回password。这里需要说明一下,这边的password其实是个密钥,只要能提供这个密钥,系统便会赋予相应的身份。换句话说,上面创建的sensor-100可以提供这个密钥以获得sensor-principle身份,sensor-200如果能够提供同样的密钥,系统也会把它辨识成同样的身份,拥有身份上面所对应的一切权限。

用以下命令把这个身份绑定在设备上:

1
bce.py iot attach-thing-principal --endpoint-name "smart-project" --thing-name "sensor-100" --principal-name "sensor-principle"

下面创建策略(Policy),以控制对消息主题的订阅发布等操作权限。比如,用于订阅和发布某公司B楼第5层的温度的主题,实现方式如下:

1
bce.py iot create-policy --endpoint-name "smart-project" --policy-name "b-5-temperature-policy" --topic="building-b/floor-5/temperature" --operation=PUBLISH --operation=SUBSCRIBE

创建策略成功后,便可以绑定到身份上,拥有这个身份的设备sensor-100便继承了对主题的订阅发布权限:

1
bce.py iot attach-principal-policy --endpoint-name "smart-project" --policy-name "b-5-temperature-policy" --principal-name "sensor-principle"

运维人员体验至此结束,物联网服务已经包含了一个设置好了访问权限的设备。

开发体验

下面我们看一下开发人员体验。

本质上开发人员只需要按照MQTT协议编程即可,具体的规范请参考http://mqtt.org/。实际上,由于MQTT是物联网的标准协议,有着丰富的客户端支持,比如Eclipse基金会提供的Paho支持Windows/Unix/Mac/Android/RTOS上C/C++/Java/Python/JavaScript/.Net语言的开发。

这里我们就以NetBeans开发环境编写Java应用为例。新建一个Java应用程序类型的Maven项目,右击“依赖关系”选择添加依赖关系,查询org.eclipse.paho,并加入对org.eclipse.paho.client.mqttv3的依赖,并在main函数中加入以下代码:

String endpoint = "smart-project";
String username = "smart-project/sensor-100";
String password = "Dm3yyvOHb7zt/uRWadfasdfMc+uDbf4j960=";
String topic = "building-b/floor-5/temperature";
 
// 创建SSL连接
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init((KeyStore)null);
TrustManager[] trustManagers = tmf.getTrustManagers();
 
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, trustManagers, null);
 
// 配置MQTT连接
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setUserName(username);
options.setPassword(password.toCharArray());
options.setSocketFactory(ctx.getSocketFactory());
 
// 创建MQTT连接
MqttClient client = new MqttClient(endpoint, "java-client");
client.connect(options);
 
// 发送消息
MqttMessage message = new MqttMessage();
message.setPayload("15".getBytes());
client.publish(topic, message);
client.disconnect();

把以上代码植入智能设备,便可以轻松安全地向云端发送消息了。从云端向智能设备发送控制命令也很直观,这里就不再赘述了。

可以看见,采用云端的托管物联网服务,把基础架构与运维交给云服务供应商,使得物联网项目实施高效便捷了许多。百度开放云物联网服务为物联网而生,不但提供了全托管的MQTT服务,在安全性与可扩展性方面也做下足了功夫,诚意十足。

IOT---MQTT 优缺点

物联网并不仅仅是一种网络,而是一个新的生态环境,它描述的本质是越来越多的使用物品通过网络连接在一起并可使用单个或者多个的终端设备对它们进行各种控制和使用—当然,工业上的物联网通常连接到的石鼓传感器或者其他数据采集仪器以及行为单位。思科曾经预测过,物联网市场的规模可能在14万亿美金左右,前景极为光明。众所周知,物联网是在传统互联网基础上延伸和扩展而出的概念,用户端从传统的计算机延伸和扩展到了任何物品与物品之间,而物品则通过各种传感器进行信息采集,然后通过计算设备进行网络信息交换与通信。但是当前移动互联网正处于起步阶段,很多时候无法提供可靠的网络保障,因此,IBM主导并提出了MQTT协议,致力于解决这一方面的问题。

什么是MQTT协议?

MQTT是一个由IBM主导开发的物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。它的核心设计思想是开源、可靠、轻巧、简单,具有以下主要的几项特性:
1.  非常小的通信开销(最小的消息大小为 2 字节);
2.  支持各种流行编程语言(包括C,Java,Ruby,Python 等等)且易于使用的客户端;
3.  支持发布 / 预定模型,简化应用程序的开发;
4.  提供三种不同消息传递等级,让消息能按需到达目的地,适应在不稳定工作的网络传输需求

 

对于传统的HTTP和MQ协议,MQTT的优势在哪里呢?这有一张表格能清楚的展示这一点
 

低协议开销

MQTT 的独特之处在于,它的每消息标题可以短至 2 个字节。MQ 和 HTTP 都拥有高得多的每消息开销。对于 HTTP,为每个新请求消息重新建立 HTTP 连接会导致重大的开销。MQ 和 MQTT 所使用的永久连接显著减少了这一开销。

对不稳定网络的容忍

MQTT 和 MQ 能够从断开等故障中恢复,而且没有进一步的代码需求。但是,HTTP 无法原生地实现此目的,需要客户端重试编码,这可能增加幂等性问题。
低功耗
MQTT 是专门针对低功耗目标而设计的。HTTP 的设计没有考虑此因素,因此增加了功耗。
数百万个连接的客户端
在 HTTP 堆栈上,维护数百万个并发连接,需要做许多的工作来提供支持。尽管可以实现此支持,但大多数商业产品都为处理这一数量级的永久连接而进行了优化。IBM 提供了 IBM MessageSight,这是一个单机架装载服务器,经过测试能处理多达 100 万个通过 MQTT 并发连接的设备。相反,MQ 不是为大量并发客户端而设计的。
推送通知
您需要能够及时地将通知传递给客户。为此,必须采用某种定期轮询或推送方法;从电池、系统负载和带宽角度讲,推送是最佳解决方案。
我们的企业可能需要在没有第三方中介的情况下发送敏感的信息。这降低了特定于操作系统的解决方案(比如 Apple iOS、Google Play 通知)作为主要传输机制的价值。
HTTP 只允许使用一种称为COMET 的方法,使用持久的 HTTP 请求来执行推送。从客户端和服务器的角度讲,此方法都很昂贵。MQ 和 MQTT 都支持推送,这是它们的一个基本特性
客户端平台差异
HTTP 和 MQTT 客户端都已在大量平台上实现。MQTT 的简单性有助于以极少的精力在额外的客户端上实现 MQTT。
防火墙容错
一些企业防火墙将出站连接限制到一些已定义的端口。这些端口通常被限制为 HTTP(80 端口)、HTTPS(443 端口)等。HTTP 显然可以在这些情况下运行。MQTT 可封装在一个 WebSockets 连接中,显示为一个 HTTP 升级请求,从而允许在这些情况下运行。MQ 不允许采用这种模式。
事实上,MQTT的应用非常之广泛,几乎现在随便找一家大型的硬件、互联网企业,都可以找到MQTT的身影,例如Facebook、BP、alibaba、baidu等等
 
MQTT协议的缺陷以及MQTT+概念的提出
由于MQTT本身的各项技术优势,越来越多的企业倾向于选用MQTT作为物联网产品通讯的标准协议,也因此,工程师们渐渐发现MQTT协议要想大规模商用,也有一些有待完善的功能。比如:
 
——没有齐备的SDK,不同的异构终端,需要有对应的与MQTT服务器通信的软件SDK包,比如MCU、Linux、Android、IOS、WEB等之间要实现互联互通必然需要不同的SDK包
——不支持File和AV,有些应用场景,需要传输的信息可能不仅仅限于指令,比如声音信号和视频信号,这些需要通过File和AV来实现通信。
——不支持与第三方HTTP的集成,虽然MQTT协议优于普通的HTTP协议,但是基于传统的HTTP协议的WEB服务器仍然占主流市场,那么这些服务器要实现与MQTT协议的互联互通,以降低升级成本也尤为关键。
——不支持负载均衡,为防止高并发和恶意攻击,负载均衡服务器也必不可少。
——不支持用户管理接口,用户在进行设备的行为数据分析的时候,显得尤为重要,这又是工业4.0、大数据时代的必然需求。
——不支持离线消息,弥补设备离线以后,MQTT服务器对设备的控制信息丢失的问题。
——不支持点对点通信,采用标准的MQTT协议,理论上可以通过相互订阅的方式实现点对点通信,但是逻辑相对复杂,并且对设备的安全性方面存在担忧。当设备B和设备C在同一主题的情况下,设备A无法知道是设备B还是设备C发送的消息,也有可能消息被设备D窃听。 
——不支持群通信和群管理,实现了对群组成员的管理,群组成员之间能互通消息,这在一个设备被多人控制,或者多个设备被一人控制的这种场景下,尤为有用。

这些问题阻碍了MQTT技术在国内市场的进一步发展,毕竟对于单个的公司或者工程师而言,想要解决它们需要耗费大量的资源和时间,并且稳定性的验证也需要一个较长的时间周期。但近期,国内的一支物联网开发团队经过两年艰苦的研发和商业化验证,在MQTT协议的基础上,正式提出了一套新的解决方案,称之为ET-iLink MQTT+物联网解决方案,团队同步公布了其中的一些细节和技术指标,引起了业界的关注。
 
MQTT+连接云是什么?
ET-iLink MQTT+物联网解决方案是一套综合性的方案,下图是使用MQTT+作为设备接入协议的整体解决方案框图。

 

设备使用MQTT+客户端可以在特定的主题上发布消息,也可以通过订阅特定的主题以接收其他设备或者用户发布的消息,从而实现M2M,M2P,P2M的通信。
云网关LB Sever负责设备的接入,协议适配,消息转发等功能,如果要支持海量设备的接入,LB Sever集群是必须的。
设备管理负责设备接入认证,设备与用户绑定,操作授权等相关的功能。
账号管理负责用户账号安全认证,授权认证等相关的功能,同时也支持第三方账号安全认证。
云服务负责设备业务逻辑。不同的设备厂商都有一套自己的业务逻辑和服务,这种服务可以和容易的运行在云端提供的容器中,使用基于容器的微服务使得应用程序能够更快地进行创建,并且更易于维护,同时又能够得到更高的质量。而数据的存储和分析使用云平台提供的通用的存储服务和大数据分析引擎。

 

用户只要注册账号,绑定设备,就可以通过手机APP,微信或者web等终端轻松查看设备信息,与设备进行交互操作。

此解决方案具有的优势有:
·移动设备
能在 8bit 位处理器上很好的运行 C /JavaScript/Java 的 client 库分别只有 30/75/100KB
在移动设备上耗电率低,大约只需要 HTTP 的一半
·很好的适应各种复杂网络,特别是受限网络
预期并适应频繁的网络中断,能应对低速、低质量的网络
压缩优化过后的协议,可以有效降低网络流量,从而节约网络成本
完成同样的数据通信,MQTT只需要 HTTP 约 1/4 得数据流量
·发布 - 订阅的消息通信协议,允许一条消息只发布一次,便可被多个消费端(应用程序 / 设备)所接收
·能够实现设备与设备之间的点对点的双向通信。
·对HTTP接口的兼容,能实现系统间松耦合,简化开发,方便扩展,整合。
·提供灵活便捷的系统整合能力
使用微服务+docker的方式,快速部署高效运行云端服务
提供可靠的设备管理和账号管理体系,您只需要关注核心业务
提供通用的数据存储和数据分析服务
提供与第三方云平台的对接功能
提供协议适配功能,客户端可以使用多种通信协议与设备进行通信。
·提供丰富的安全性
使用 SSL 提供的认证和加密来保证传输安全性
采用账号安全认证+设备安全认证结合的方式保证内容安全
·强大的性能提高系统的高可靠性
高连接数下系统低计算资源使用
高连接数下系统高信息处理速度
·提供多种消息服务质量,满足不同场景需求
0 :消息最多被传递一次,比如一般类广告,通知
1 :消息会被传递但可能会重复传递,比如账户余额通知
2 :消息保证传递且仅有一次传递,比如交易支付批复通知
 
硬件+软件+私有云平台开发套件/免费的公有云平台支持
 
小e MQTT系列全功能开发板是为了帮助工程师们快速实现物联网项目的开发而提供一款配套开发板。考虑到实际的项目应用环境,它有两个不同的版本:

 

小e1Wi-Fi全功能开发板采用ESP8266 WiFi SOC 芯片,采用Free RTOS实时操作系统,主频可达160MHZ。支持标准的 IEEE802.11 b/g/n 协议,完整的 TCP/IP 协议栈,具有丰富的硬件接口,并配备OLED屏,温湿度传感器,大气压传感器,RGB,IR等,利用微信进行远程控制与语音互动,代码开源。

小e2 2G透明串口开发板,是利用SIM卡和运营商的GPRS网络提供无线数据传输功能的开发板,通过此开发板的2G模块,可以提供各种设备(PC、手机、服务器)到模块间的透明的数据交互

 

参考地址:

管理控制台: https://www.jianshu.com/p/ae76ac570f51

IOT(9)---MQTT 优缺点:https://blog.csdn.net/zhangbijun1230/article/details/79755138

 

posted @ 2019-07-22 16:37  逐梦客!  阅读(4279)  评论(0编辑  收藏  举报