MQTT开发杂记

封面

tl;dr

由于毕设需要用到mqtt网络协议栈,但这个协议我一直没用过,所以打算写这篇博客来记录一下搭建过程。

MQTT的工作流程

这是一个需要中心化服务器的协议。中心服务器通常称为broker
MQTT(Message Queuing Telemetry Transport) 是一种轻量级的、基于发布/订阅模式的通信协议,常用于物联网设备之间的通信废话
其工作流程如下:

  1. 连接建立阶段
    • 客户端通过TCP连接到MQTT代理服务器(通常称为MQTT Broker)。
    • 客户端发送CONNECT报文,包含客户端ID、用户名、密码等信息。
    • 服务器响应CONNACK报文,表示连接建立成功或失败。
  2. 订阅主题
    • 客户端发送SUBSCRIBE报文,指定感兴趣的主题和QoS级别。
    • 服务器记录客户端的订阅关系。
  3. 发布消息
    • 客户端发送PUBLISH报文,包含主题和消息内容。
    • 服务器将消息传送给所有订阅了相应主题的客户端。
  4. 接收消息
    • 客户端接收到服务器发送的PUBLISH报文,获取消息内容。
  5. 取消订阅
    • 客户端发送UNSUBSCRIBE报文,取消对某个主题的订阅。
  6. 断开连接
    • 客户端或服务器可以发送DISCONNECT报文,正常断开连接。

当有n个客户端订阅了同一个主题we_are_ikun,这n个人谁都可以publish一条包含自定义内容的报文jntm,随后经由broker,会将该消息转发给包括他的所有订阅了we_are_ikun的终端上。此时,其他终端里任何一个人也可以再publish一条包含自定义消息的报文ni gan ma haha aiyo amagi,该报文会经由broker再转发给包括他的所有终端。

是不是很像一个聊天室?对没错!就想象是一群小黑子 ikun呆在同一个房间里一起谈论哥哥的篮球和背带一样,A说的话能被房间里其他人听到,B说的话也可以被其他人听到。

服务器搭建

我使用的测试服务器是运行在VMware中的Alpine Linux,连接模式选择桥接,以便可以和esp8266在同一个子网下。
我使用的客户端有两台,一台是上述虚拟机,一台是我的安卓手机,使用termux
在装好了系统的虚拟机中安装好mosquittomosquitto-clients软件包。
termux中安装mosquitto软件包,不需要安装clients包,因为它包含了mosquitto_pubmosquitto_sub两个程序。

详见GitHub issues #613

使用虚拟机和termux进行简单的MQTT通信实验

本教程参考官方repo的readme
在虚拟机中定位到配置文件/etc/mosquitto/mosquitto.conf

termux中,该配置文件的路径是/data/user/0/com.termux/files/usr/etc/mosquitto/mosquitto.conf

取消注释log_type all以将日志等级设置为all,将log_dest设置为stdout,要不然不会在屏幕上显示日志。
或者直接添加下面两行也行:我后来试了一下日志等级不设其实也ok

1
2
log_dest stdout
log_type all

添加以下两行以开启在0.0.0.0监听、允许匿名登录:

1
2
listener 1883 0.0.0.0
allow_anonymous true

虚拟机tty1中启动mosquitto服务端程序(使用默认端口1883开服):

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

进入tty2termux,订阅testTopic的主题:

1
mosquitto_sub -h 192.168.146.138 -p 1883 -t "testTopic"

进入tty3,向主题publish一条消息:

1
mosquitto_pub -h 192.168.146.138 -p 1883 -t "testTopic" -m "message from tty3"

回到tty2,看看是不是多了一条来自tty3的消息?termux里是不是也有这条消息?
进入termux,再开一个session,向主题publish一条消息:

1
mosquitto_pub -h 192.168.146.138 -p 1883 -t "testTopic" -m "message from termux"

回到上一个session,看看是不是多了这条消息?tty2里是不是也多了这条消息?

如何确保MQTT通信的安全?

这就是简单的MQTT通信实验。我们上点难度:加个鉴权
MQTT支持密码和密钥两种认证方式,我们先从密码开始。参考mqtt官方文档
进入虚拟机,停掉刚刚那个谁都可以加进来的mqtt服务器,编辑/etc/mosquitto/mosquitto.conf,将allow_anonymous设置为false,再添加一行,指向存放密码文件的路径(记得创建这个文件):

1
password_file /etc/mosquitto/passwordfile

⚠注意:在Linux上,需要将密码文件存放到/etc/mosquitto下,要不然就算你在mosquitto.conf中写入了password_file,也无法读取密码文件。

添加用户 -方法 1
/etc/mosquitto/passwordfile里写入账号和明文密码,一行一个,像这样:

1
2
user1:passwd1
usr2:pwd2

然后运行这行命令来将密码文件加密。

1
mosquitto_passwd -U passwordfile

如果有用户是在加密过之后再被添加,写了明文密码,需要再运行一次加密,但是这次加密的时候,系统会只加密明文密码,之前被加密过的密文不会被二次加密。

密码文件必须加密后才能被读取使用!

添加用户 -方法 2
现在,我们添加一个用户,叫alpine,密码a123456

1
mosquitto_passwd -c /etc/mosquitto/passwordfile alpine

然后系统会提示你输入该用户的密码,和linux设置用户密码一样。
现在,我们再添加一个用户,叫termux,密码t123456

1
mosquitto_passwd -b /etc/mosquitto/passwordfile termux t123456

注意这里的参数!
-c是在没有任何用户的情况下,初始化密码文件用。会覆盖写入文件
-b是在有用户的情况下使用。会追加写入文件。增加用户时命令行里需要传递明文密码了。

现在,我们删除一个用户,把上面的user1删了:

1
mosquitto_passwd -D /etc/mosquitto/passwordfile user1

在运行的时候,没有关闭mosquitto服务器,但添加/删除了用户,怎么重新加载配置文件呢?新开一个终端(或者tty),运行下面这个命令即可:

1
kill -HUP "$(mosquitto)"

然后就能在运行着mosquitto的终端里看到Reloading config.的提示了,此时新的用户清单会被应用。

怎么连接呢?
使用 mosquitto_sub 进行订阅,该话题下所有的消息都会显示在这里:

1
mosquitto_sub -h <broker_addr> -p <broker_port> -t <topic> -i <device_identifier> -u <username> -P <password>

使用 mosquitto_pub 往指定的话题publish内容:

1
mosquitto_pub -h <broker_address> -t <topic> -i <device_identifier> -m "message" -u <username> -P <password>

MQTT开发杂记
http://blog.coolenoch.ink/2024/03/18/13-MQTT开发杂记-240318/
作者
CoolestEnoch
发布于
2024年3月18日
许可协议