树莓派安装Mosquitto MQTT服务

https://zhuanlan.zhihu.com/p/359395794

1. 安装Mosquitto MQTT组件

  • 登录树莓派(网线连接)
  • 检查网络连通状态

pi@raspberrypi:~ $ ping www.baidu.com

如果网络不通

Win10找到这个设置界面:

先去掉勾选,确定,再重新如勾选,确定。

再测试:

网通了。

  • 更新apt的资源列表

sudo apt-get update

  • 搜索可安装的MQTT

apt search mqtt

MQTT分为服务器和客户端两部分。有很多MQTT软件包可选,我们选择比较流行的mosquitto。

  • 安装mosquitto 和mosquitto-clients

sudo apt-get install mosquitto mosquitto-clients

说明:

mosquitto – the MQTT broker(MQTT代理,即MQTT服务)

mosquitto-clients – 命令行客户端,在调试时很有用。

  • 查看已经安装的mosquitto软件包

dpkg -l mosquitto

2. 配置Mosquitto

在使用Mosquitto之前,我们需要修改配置文件。配置文件位于/etc/mosquito。

  • 查看配置文件

cat /etc/mosquitto/mosquitto.conf

注释中说:

1) 将本地配置放在/etc/mosquitto/conf.d/目录中。

我们看看/etc/mosquitto/conf.d/目录:

里面有一个说明文件,打开看看:

放置在该目录中的任何扩展名为.conf的文件都会被代理作为配置文件加载,用作本地配置。

2) 有一个完全的配置文件说明在:/usr/share/doc/mosquitto/examples/

  • 复制配置文件mosquitto.conf.gz到/etc/mosquitto/conf.d/目录

sudo cp /usr/share/doc/mosquitto/examples/mosquitto.conf.gz /etc/mosquitto/conf.d/

  • 进入/etc/mosquitto/conf.d/目录
  • 解压mosquitto.conf.gz

sudo gzip -d mosquitto.conf.gz

  • 编辑mosquitto.conf

sudo nano /etc/mosquitto/conf.d/mosquitto.conf

这是一个很大的文件,有800多行,所有的行都被#符号注释掉了。

我们修改下面几处,去掉注释符号,修改默认值:

user mosquitto

max_queued_messages 200

message_size_limit 0

allow_zero_length_clientid true

allow_duplicate_messages false

port 1883

autosave_interval 900

autosave_on_changes false

persistence true

persistence_file mosquitto.db

allow_anonymous false

Password_file /etc/mosquitto/passwd.conf

  • 退回登录时的家目录

3. 生成账号密码

下面两种方法选一种。

  • 密文创建账户

sudo Mosquitto_passwd -c /etc/mosquitto/passwd.conf 用户名

输入两遍密码

我们的用户名为ct

sudo mosquitto_passwd -c /etc/mosquitto/passwd.conf ct

  • 明文创建账户

sudo Mosquitto_passwd -b /etc/mosquitto/passwd.conf 用户名 密码

我们不用明文账户。

4. 测试Mosquitto服务

4.1 查看帮助

mosquitto -h

4.2 测试mosquitto

需要开3个终端。

  • 装载指定配置,启动mosquitto服务

mosquitto -c /etc/mosquitto/mosquitto.conf -v

-v记录所有类型的日志,因为我们在调试。以后正式使用mosquitto就不需要记录日志了,因为会占用存储空间。

上面提示日志文件mosquitto.log的权限不够:

ls -l /var/log/mosquitto/mosquitto.log

修改权限:

sudo chmod 666 /var/log/mosquitto/mosquitto.log

再执行:

mosquitto -c /etc/mosquitto/mosquitto.conf -v

服务运行,终端窗口被占用。

  • 测试publish 和subscribe

再打开两个终端:

1) 一个终端执行:

mosquitto_sub -p 1883 -u ct -P xxxxxx -t “test”

订阅subscribe主题Topic:test,等待接收消息。

2) 另一个终端执行:

mosquitto_pub -p 1883 -u ct -P xxxxxx -t test -m “Hello!”

发布主题为test的消息Hello!

3) 订阅窗口显示接收到的消息

4) 查看日志

sudo cat /var/log/mosquitto/mosquitto.log

5. 正式运行mosquitto服务

  • 重新启动树莓派

sudo reboot

  • 查看正在运行的mosquitto进程

ps -ef | grep mosquitto

mosquitto已经在后台启动。

MQTT参考

MQTT是一个专为IoT设计的OASIS标准的Pub/Sub消息协议,已经被广泛应用在汽车工业、制造业、电信业、石油和天然气业等场景。主要特点:超轻量级(内存开销约为6MB)、传输带宽小、消息可靠传输。

01 基本概念

MQTT 架构的核心组件是代理(Broker)和客户端(Client)。Broker的负责在不同的Client之间分发消息。Client有两种角色:发布者(Publisher)和订阅者(Subscriber)。向Broker发布消息的Client是Publisher,向Broker订阅消息的Client是Subscriber。一个Client可以同时既是Publisher也是Subscriber。Client只与Broker建立连接,Client之间不直接相连。这种的好处是Client之间的通信不要求双方同时在线,即使一方离线,消息也可以临时存储在Broker中,等到Client重新上线,Broker再将消息发送给它。每个消息都有一个主题(Topic),Broker正是根据Topic来决策这条消息应该发送给哪些Subscriber。

Broker能够缓冲暂时无法分发到Client的消息。这个特点很适合网络不稳定的场景,例如IoT。除此之外,为了支持可靠的消息传递,MQTT支持 3 种不同类型QoS的消息:0 – 最多一次(at most once),1 – 至少一次(at least once),2 – 恰好一次(exactly once)。具体下文会介绍。

目前MQTT协议有两个版本:MQTT 3.1.1 和 MQTT 5。大多数商业 MQTT Broker现在都支持 MQTT 5,但许多物联网托管云服务仅支持 MQTT 3.1.1。相比MQTT 3.11,MQTT 5具有更强大的系统和云原生可扩展性。

Topic

在MQTT中,Topic指的一个UTF-8编码的字符串,Broker根据Topic为每个Client过滤它应该获取的消息。每个Topic由一个或多个主题级别构成,正斜杠“/”是主题级别分隔符。下图就是一个Topic的例子,可以看到,它是一个四级的Topic。通过使用“/”,可以让Topic的含义更加清晰和便于理解,下图表达的是“我家一楼客厅的温度”这一主题。MQTT的Topic非常轻量级,Client在发布或者订阅它之前不需要专门创建。Broker会接受每一个符合规则的Topic。

每个Topic必须至少包含一个字符,允许空格(但是不推荐包含空格),大小写敏感(例如“myhome/firstfloor”和“Myhome/firstfloor”是两个不同的Topic)。注意:不要以$符号开头设置Topic,因为以$符号开头的topic保留给Broker的内部统计。

Topic在匹配时支持通配符,MQTT支持两种通配符:单级的通配符“+”,多级的通配符“#”。注意:多级通配符必须作为主题的最后一个字符放置,并在前面加上正斜杠。

单级通配符举例:

多级通配符举例:

定义Topic的几大原则:

  • 首字符不要使用斜杠。这会引入一个不必要的主题级别和零字符,零字符没有任何好处,经常会导致混乱。
  • 不要在主题中使用空格。尽管MQTT不禁止空格,但是为了阅读和调试的方便,请不要使用空格。
  • 保持Topic简短。尽可能使Topic简短,否则可能给小型设备带来额外的开销。
  • 只使用ASCII字符,避免不可打印的字符。不可打印的字符会导致调试困难。
  • 将唯一标识符或ClientID嵌入到主题中。方便识别消息的发送方,便于调试和鉴权。
  • 不要订阅#。接收所有的消息可能会导致Client承受不了巨大的负载,进而导致设备故障。
  • 主题的设置要考虑扩展性。主题设置要便于后续扩展。
  • 使用定义精确的Topic而不要使用定义模糊的Topic。当命名Topic时,尽可能对它们进行区分。

Client

Client指连接Broker的客户端。一个Client可以是Publisher,也可以是Subscriber,还可以两个身份都拥有。是Publisher还是Subscriber主要由Client的行为定义,发布消息的称之为Publisher,订阅消息的称之为Subscriber。

一个MQTT Client可以是任何设备(从微控制器到完整的服务器),只要它运行了MQTT库并且通过网络连上了Broker。

Broker

与Client对应的是Broker,它负责接收所有消息,过滤消息,确定订阅了消息的Client,并将消息发送给这些订阅的Client。除此之外,Broker还要负责管理和保存Client的持久会话的数据、对Client的身份认证和授权等等。

MQTT连接

MQTT协议基于TCP/IP,因此Client和Broker都需要一个TCP/IP协议栈。除此之外,MQTT也支持Websocket协议,当然,Websocket也是基于TCP的。目的是使得浏览器可以使用MQTT协议,因为浏览器无法直接操控TCP会话,但是可以操作Websocket会话。

MQTT连接只会在Client和Broker之间建立。Client之间不会直接建立连接。要创建连接,Client先向Broker发送CONNECT消息,Broker以CONNACK消息和状态代码进行响应。一旦连接建立,Broker将其保持打开,直到Client发送断开连接命令或连接中断。

02 QoS保障

QoS保障是指消息发送方和消息接收方之间(既指消息从Client到Broker,也指消息从Broker到Client),用于定义特定消息的交付保证。消息从Client到Broker的QoS级别,由Client在发送消息时定义。消息从Broker到Client的QoS级别,由Client在订阅过程中定义。MQTT设置了三个级别:

  • At most once (0)
  • At least once (1)
  • Exactly once (2)

At most once

该级别只保证best-effort的消息发送。消息接收方不会确认收到消息,发送方也不会存储和重新发送消息。消息只会被发送方发送一次,称之为“即发即忘”。

At least once

该级别保证消息至少发送一次。消息发送方发送完消息后,会等待消息接收方返回的PUBACK数据包,用来确认消息接收方确实收到了消息。如果消息发送方在一段时间内没有收到消息接收方的PUBACK包,它会再次发送这个消息,直到收到PUBACK包。注意:这可能会导致消息的重复发送,因此需要信息的订阅者自己处理重复消息。

Exactly once

该级别保证消息会且仅会被收到一次。这个级别的QoS是最安全的,也是最慢的,因为它需要两个请求/响应往返。消息发送方在发送完消息后,会等待消息接收方返回的PUBREC包。一旦消息发送方收到PUBREC包,它会丢弃原始的消息,保存收到的PUBREC包,并发送PUBREL数据包给消息接收方和等待返回的PUBCOMP包。消息的接收者直到发送PUBCOMP之后,才会确认一开始收到的消息的ID。这样做的目的是防止处理重复的消息。最终,消息的发送者和接收者都确认了消息已经成功发送。

03 持久会话

在非持久会话中,如果Client在订阅过程中因为种种原因掉线了,那么所有的未被接收的消息都会丢失。为了避免上述问题,Client在与Broker创建连接时,可以设置持久会话,这样Client在重新连上后,掉线期间的消息(QoS 1和QoS 2)将不会丢失并可以被正确获取。

Client在和Broker创建连接时,通过设置cleanSession标志位来告诉Broker创建哪种会话:

  • True:非持久会话
  • False:持久会话

04 保留消息

保留消息指的是retained标志位被置为true的普通消息。Broker会保留最后一条收到的保留消息,这样新订阅的Client可以在它们订阅主题后立刻获得一条消息。

保留消息的主要应用在Client想要在订阅主题后就需要立刻获取消息的场景。如果没有保留消息,Client就需要等待消息发布者发布下一条消息,才能知道消息发布者的状态。由于消息发布者的发布频率是不确定的,在某些特殊场景,Client很可能要等待很久才能获取到第一条消息。

05 遗嘱

Client可以使用遗嘱功能在自己异常离线后通知其他Client。遗嘱消息是一条普通的MQTT消息,带有一个Topic、Retained message标志位、QoS标志位和有效负载。遗嘱消息在Client与Broker创建连接时发送给Broker。Broker会存储遗嘱消息,当发现Client异常离线后,将这条遗嘱消息发送给订阅了遗嘱消息Topic的所有Client。如果Client使用DISCONNECT消息正常断开连接,那么Broker将会丢弃存储的遗嘱消息。

06 MQTT和消息队列(MQ)的区别

MQTT的名字中含有MQ,但是其实与消息队列无关。通常可以看到MQTT与传统消息队列存在以下区别:

  • 消息队列存储消息,直到消息被消费。如果没有消费者消费消息,那么消息会阻塞在队列中。
  • 消息队列中,一个消息只能被一个消费者消费。传统的消息队列,一个队列只能被一个消费者消费。而MQTT中,所有的订阅者都可以得到被订阅主题的消息。
  • 消息队列必须被显式命名和创建。消息队列比Topic要严格的多。队列在使用前,必须用单独的命令进行创建。只有在创建后,队列才能被用来生产和消费消息。MQTT的Topic就相对灵活,可以随时创建。