初识MQTT与mosquitto

最近,接手一个新的项目 —— 电子价签。对于电子价签的常见架构,阿里云有一篇文章描述的非常详细(网址见文章末尾),里面包含一个核心的概念 MQTT。由于第一次接触MQTT,特此整理相关知识点,以备后用。

MQTT是什么

MQTT (Message Queuing Telemetry Transport 消息队列遥测传输),是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。

mqtt官网 https://mqtt.org

  • MQTT 是 IBM 推出的一种针对移动端设备的基于 TCP/IP 的发布、订阅协议
  • 可以连接大量的远程传感器和控制设备(MQTT特点是可以保持长连接,具有一定的实时性)
  • 云端向设备发送消息,设备端可以在最短时间内接收到并作出响应
  • MQTT 适合需要实时控制的场合

MQTT协议特性

  • 使用发布、订阅消息模式。提供一对多的消息发布,解除应用程序耦合
  • 有三种消息发布服务质量(QoS0、QoS1、QoS2)
    • 最多一次 消息发布完全依赖底层 TCP/IP 网络,会发生消息丢失或重复。适合对数据要求不严格的情况
    • 最少一次 确保消息一定会到达,但消息可能会重复。大部分业务使用该方式
    • 只有一次 确保消息只到达一次,不会重复、不会丢失。适合要求严格的系统,例如:计费系统等
  • 小型传输,开销很小,协议交换最小化,以降低网络流量
  • 允许动态创建主题
  • 假设数据不可知,不强求传输数据的类型与格式,保持灵活性
  • 客户端可以设置遗嘱用于通知订阅者异常情况

关于MQTT遗嘱(last will)

MQTT 可以设置遗嘱,客户端在连接Broker的时候将遗嘱内容 (也是 topic+payload 形式,遗嘱也有一个主题)发送给Broker并保存在Broker中,当客户端因为非正常原因断开与Broker的连接时,Broker会将遗嘱信息发送给订阅了该主题(订阅遗嘱的主题)的客户端。客户端正常调用DISCONNECT 断开连接时属于正常断开连接,Broker 不会发送遗嘱,而且会将遗嘱从 Broker 中删除。

遗嘱消息发布的条件,包括但不限于:

  • 服务端检测到了一个I/O错误或者网络故障。
  • 客户端在爆出连接(Keep Alive)的时间内未能通讯。
  • 客户端没有发送DISCONNECT保温直接关闭了网络连接。
  • 由于协议错误服务端关闭了网络连接。

一旦被发布或者服务端收到了客户端发送的DISCONNECT报文,遗嘱消息就必须从存储的会话状态中移除。

MQTT协议中的几个重要概念

  • 服务端(broker)
    发送消息的客户端和请求订阅的客户端之间的中介(broker)。它接收来自客户端的网络连接,接收客户端发布的消息,处理客户端的订阅和取消订阅请求,转发相应消息给符合条件的已订阅客户端。

  • 客户端
    分为:发布客户端(publishing)、订阅客户端(subscribing)。都与 broker 相连,通过 broker 进行数据交换与传递。

  • 订阅
    订阅包含一个主题过滤器和一个最大的服务质量(QoS)等级。
    订阅客户端(subscribing)只有订阅了相关主题时,才能接收到对应主题(topic)的消息。
    发布客户端(publishing)只能把消息发送到指定的订阅主题中。

有没有让你想到消息中间价,例如:kafka、rocketMQ 等。

mosquitto

mosquitto 是一款实现了 MQTT 协议的开源消息代理(broker)软件,同时也包含订阅者和发布者命令行工具。

官方地址:https://mosquitto.org
官方文档:https://mosquitto.org/documentation

mac 安装 mosquitto

https://mosquitto.org/download

这里使用最简单的 brew 方式安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
brew install mosquitto

### 安装成功之后有下面提示内容 ###

mosquitto has been installed with a default configuration file.
You can make changes to the configuration by editing:
/usr/local/etc/mosquitto/mosquitto.conf

To have launchd start mosquitto now and restart at login:
brew services start mosquitto

Or, if you don't want/need a background service you can just run:
mosquitto -c /usr/local/etc/mosquitto/mosquitto.conf
==> Summary
/usr/local/Cellar/mosquitto/2.0.10_1: 43 files, 1.7MB
==> Caveats
==> mosquitto
mosquitto has been installed with a default configuration file.
You can make changes to the configuration by editing:
/usr/local/etc/mosquitto/mosquitto.conf

To have launchd start mosquitto now and restart at login:
brew services start mosquitto
Or, if you don't want/need a background service you can just run:
mosquitto -c /usr/local/etc/mosquitto/mosquitto.conf

可以看到有两种启动方式:

  1. brew services start mosquitto

    使用默认配置启动,并作为后台进程提供服务(为了方便演示,使用此方法启动)

  2. mosquitto -c /usr/local/etc/mosquitto/mosquitto.conf

    启动时会根据配置文件 /usr/local/etc/mosquitto/mosquitto.conf 进行设置

使用命令行进行发布、订阅

命令行参数含义
-h:服务器主机,默认localhost
-t:指定主题
-u:用户名
-P:密码
-i:客户端id,唯一
-m:发布的消息内容

1
2
3
4
5
6
7
8
9
10
11
12
## 终端1,订阅主题 helloworld
## 要先启动 消息订阅,启动之后一直阻塞监听主题
## -v 显示详细信息
## -t表示主题
➜ ~ mosquitto_sub -v -t helloworld
helloworld i am coming
helloworld i am coming again


## 终端2,向主题 helloworld 发布两次消息
➜ ~ mosquitto_pub -t helloworld -m "i am coming"
➜ ~ mosquitto_pub -t helloworld -m "i am coming again"

此时,默认是不需要认证的,并且连接的 broker 为 localhost
如需认证,设置配置文件 /usr/local/etc/mosquitto/mosquitto.conf,并通过配置文件启动服务

mosquitto.conf 核心配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# 客户端心跳的间隔时间
#retry_interval 20

# 系统状态的刷新时间
#sys_interval 10

# 系统资源的回收时间,0表示尽快处理
#store_clean_interval 10

# 服务进程的PID
#pid_file /var/run/mosquitto.pid

# 服务进程的系统用户
#user mosquitto

# 客户端心跳消息的最大并发数
#max_inflight_messages 10

# 客户端心跳消息缓存队列
#max_queued_messages 100

# 用于设置客户端长连接的过期时间,默认永不过期
#persistent_client_expiration

# =================================================================
# Default listener
# =================================================================

# 服务绑定的IP地址
#bind_address

# 服务绑定的端口号
#port 1883

# 允许的最大连接数,-1表示没有限制
#max_connections -1

# cafile:CA证书文件
# capath:CA证书目录
# certfile:PEM证书文件
# keyfile:PEM密钥文件
#cafile
#capath
#certfile
#keyfile

# 必须提供证书以保证数据安全性
#require_certificate false

# 若require_certificate值为true,use_identity_as_username也必须为true
#use_identity_as_username false

# 启用PSK(Pre-shared-key)支持
#psk_hint

# SSL/TSL加密算法,可以使用“openssl ciphers”命令获取
# as the output of that command.
#ciphers

# =================================================================
# Persistence
# =================================================================

# 消息自动保存的间隔时间
#autosave_interval 1800

# 消息自动保存功能的开关
#autosave_on_changes false

# 持久化功能的开关
persistence true

# 持久化DB文件
#persistence_file mosquitto.db

# 持久化DB文件目录
#persistence_location /var/lib/mosquitto/

# =================================================================
# Logging
# =================================================================

# 4种日志模式:stdout、stderr、syslog、topic
# none 则表示不记日志,此配置可以提升些许性能
log_dest none

# 选择日志的级别(可设置多项)
#log_type error
#log_type warning
#log_type notice
#log_type information

# 是否记录客户端连接信息
#connection_messages true

# 是否记录日志时间
#log_timestamp true

# =================================================================
# Security
# =================================================================

# 客户端ID的前缀限制,可用于保证安全性
#clientid_prefixes

# 允许匿名用户
#allow_anonymous true

# 用户/密码文件,默认格式:username:password
#password_file

# PSK格式密码文件,默认格式:identity:key
#psk_file

# pattern write sensor/%u/data
# ACL权限配置,常用语法如下:
# 用户限制:user <username>
# 话题限制:topic [read|write] <topic>
# 正则限制:pattern write sensor/%u/data
#acl_file

# =================================================================
# Bridges
# =================================================================

# 允许服务之间使用“桥接”模式(可用于分布式部署)
#connection <name>
#address <host>[:<port>]
#topic <topic> [[[out | in | both] qos-level] local-prefix remote-prefix]

# 设置桥接的客户端ID
#clientid

# 桥接断开时,是否清除远程服务器中的消息
#cleansession false

# 是否发布桥接的状态信息
#notifications true

# 设置桥接模式下,消息将会发布到的话题地址
# $SYS/broker/connection/<clientid>/state
#notification_topic

# 设置桥接的keepalive数值
#keepalive_interval 60

# 桥接模式,目前有三种:automatic、lazy、once
#start_type automatic

# 桥接模式automatic的超时时间
#restart_timeout 30

# 桥接模式lazy的超时时间
#idle_timeout 60

# 桥接客户端的用户名
#username

# 桥接客户端的密码
#password

# bridge_cafile:桥接客户端的CA证书文件
# bridge_capath:桥接客户端的CA证书目录
# bridge_certfile:桥接客户端的PEM证书文件
# bridge_keyfile:桥接客户端的PEM密钥文件
#bridge_cafile
#bridge_capath
#bridge_certfile
#bridge_keyfile

# 自己的配置可以放到以下目录中
include_dir /etc/mosquitto/conf.d

mqtt 客户端 mqttx

使用时,如果可以通过客户端软件操作会更加的便捷、方便。那么,mqttx 绝对会是你的首选。

mqttx 官网: https://mqttx.app/zh

mqttx 同时可以支持订阅/发布操作,非常直观的图形化界面展示。

扩展阅读