MQTT协议学习笔记

MQTT是一个基于客户端-服务器的消息发布/订阅传输协议,在我们的CSPSVR中用于与原创TSP端建立一个网络连接,所以很有必要先了解一下MQTT在网络的应用层是如何组织协议并完成通信的。
基本特征:
使用TCP/IP提供基础网络连接
使用发布/订阅消息模式,提供了一对多的消息分发和应用之间的解耦。
消息传输对有效载荷内容不可知
提供三种等级的服务质量:

“最多一次”,尽操作环境所能提供的最大努力分发消息。消息可能会丢失。例如,这个等级可用于环境传感器数据,单次的数据丢失没关系,因为不久之后会再次发送。
“至少一次”,保证消息可以到达,但是可能会重复。
“仅一次”,保证消息只到达一次。例如,这个等级可用在一个计费系统中,这里如果消息重复或丢失会导致不正确的收费。
很小的传输消耗和协议数据交换,最大限度减少网络流量。
轻量传输,开销很小(固定头部的长度只有2字节),协议交换最小化,以降低网络流量
提供一种机制,当客户端异常中断时,利用 Last Will 和 Testament 特性来通知有关各方

客户端 Client
使用MQTT的程序或设备。客户端总是通过网络连接到服务端。它可以
打开连接到服务端的网络连接
发布应用消息给其它相关的客户端
订阅以请求接受相关的应用消息
取消订阅以移除接受应用消息的请求
关闭连接到服务端的网络连接

服务端 Server
一个程序或设备,作为发送消息的客户端和请求订阅的客户端之间的中介。服务端
接受来自客户端的网络连接
接受客户端发布的应用消息
处理客户端的订阅和取消订阅请求
转发应用消息给符合条件的已订阅客户端
关闭来自客户端的网络连接

MQTT控制报文由三部分组成

Fixed Header固定报头(2Byte)所有控制报文都包含
Variable Header 可变报头,部分控制报文包含
Payload 有效载荷,部分控制报文包含

固定报头的格式 Fixed Header format

比特位 7 6 5 4 | 3 2 1 0
byte 1 MQTT控制报文的类型 用于指定控制报文类型的标志位
byte 2… 剩余长度

Reserved 	0 禁止				保留
CONNECT 	1 客户端到服务端	客户端请求连接服务端
CONNACK 	2 服务端到客户端	连接报文确认
PUBLISH 	3 两个方向都允许	发布消息
PUBACK 		4 两个方向都允许	QoS 1消息发布收到确认
PUBREC 		5 两个方向都允许	发布收到(保证交付第一步)
PUBREL 		6 两个方向都允许	发布释放(保证交付第二步)
PUBCOMP 	7 两个方向都允许	QoS 2消息发布完成(保证交互第三步)
SUBSCRIBE 	8 客户端到服务端	客户端订阅请求
SUBACK 		9 服务端到客户端	订阅请求报文确认
UNSUBSCRIBE 10 客户端到服务端	客户端取消订阅请求
UNSUBACK 	11 服务端到客户端	取消订阅报文确认
PINGREQ 	12 客户端到服务端	心跳请求
PINGRESP 	13 服务端到客户端	心跳响应
DISCONNECT 	14 客户端到服务端	客户端断开连接
Reserved 	15 禁止				保留

客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文
在一个网络连接上,客户端只能发送一次CONNECT报文。服务端必须将客户端发送的第二个CONNECT报文当作协议违规处理并断开客户端的连接

1. 引入mosquitto仓库并更新
	$sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa
	$sudo apt-get update

2. 执行以下命令安装mosquitto包
	$sudo apt-get install mosquitto

3. 安装mosquitto开发包
	$sudo apt-get install libmosquitto-dev

4. 安装mosquitto客户端
	$sudo apt-get install mosquitto-clients

5. 查询mosquitto是否正确运行
	$sudo service mosquitto status 

sudo service mosquitto start
sudo service mosquitto stop
  1. 本机测试
    打开一个终端,执行以下命令订阅主题"mqtt"
    $mosquitto_sub -h localhost -t “mqtt” -v

打开另外一个终端,发布消息到主题 “mqtt”
$mosquitto_pub -h localhost -t “mqtt” -m “Hello MQTT”

现在你会看到消息被显示在前一个终端上了.

  1. 网络测试(test.mosquitto.org)
    从test.mosquitto.org订阅所有主题,任何人发布的任何消息你都可以收到,你会看到大量有趣消息滚动在你的屏幕上。
    你也可以发布一些有趣的消息,所有订阅的人也同样会收到。

$mosquitto_sub -h test.mosquitto.org -t “#” -v

当然,你也可以只订阅特定主题,用来接收你自己的消息

$mosquitto_sub -h test.mosquitto.org -t “msg_only_from_me” -v

在另外一个终端上发布消息到特定主题,消息"My cat is Luna"应该会显示在上一个终端上
$mosquitto_pub -h test.mosquitto.org -t “msg_only_from_me” -m “My cat is Luna”

test.mosquitto.org 支持加密和不加密MQTT消息模式,也支持用TCP或者Websocket作为承载,可以通过wireshark抓包来观察不同的包格式.

配置MQTT密码
Mosquitto包含一个工具,用于生成一个特殊的密码文件,名为mosquitto_passwd。此工具将提示您输入指定用户名的密码,并将结果放在/etc/mosquitto/passwd
sudo mosquitto_passwd -c /etc/mosquitto/passwd sammy

现在,我们将替换默认的配置文件,并告诉Mosquito使用这个密码文件来要求所有连接的登录。

sudo nano /etc/mosquitto/mosquitto.conf
这应该打开一个空文件。粘贴如下:

allow_anonymous false
password_file /etc/mosquitto/passwd
allow_anonymous false将禁用所有未经身份验证的连接,并且password_file告诉Mosquitto在哪里查找用户和密码,保存并退出文件。

现在我们需要重新启动Mosquitto并测试。

sudo systemctl restart mosquitto
尝试在没有密码的情况下发布消息。

mosquitto_pub -h localhost -t “test” -m “hello world”
你应该看到被拒绝的信息:

Connection Refused: not authorised.
Error: The connection was refused.

mosquitto配置文件/etc/mosquitto/mosquitto.conf配置参数详细说明

# =================================================================
# General configuration
# =================================================================

# 客户端心跳的间隔时间
#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服务,
# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example

pid_file /var/run/mosquitto.pid

persistence true
persistence_location /var/lib/mosquitto/

log_dest file /var/log/mosquitto/mosquitto.log

include_dir /etc/mosquitto/conf.d

浏览已安装的程序。要查看已安装的软件包列表,请输入以下命令。请注意你希望卸载的软件包的名称。

dpkg --list

卸载程序和所有配置文件。在终端中输入以下命令,把替换成你希望完全移除的程序:

sudo apt-get --purge remove

只卸载程序。如果你移除程序但保留配置文件,请输入以下命令:

sudo apt-get remove

搭建EMQ
git clone https://github.com/emqx/emqx-rel.git
cd emqx-rel && make
cd _rel/emqx && ./bin/emqx console

或者直接下载二进制文件

wget https://www.emqx.io/downloads/enterprise/v3.4.2/emqx-ee-ubuntu18.04-v3.4.2_amd64.deb

sudo dpkg -i emqx-ee-ubuntu18.04-v3.4.2_amd64.deb

wget https://www.emqx.io/downloads/enterprise/v3.4.2/emqx-ee-ubuntu18.04-v3.4.2.zip

解压后执行如下

# Start emqx
./bin/emqx start

# Check Status
./bin/emqx_ctl status

# Stop emqx
./bin/emqx stop

控制台地址: http://127.0.0.1:18083,默认用户名: admin,密码:public

SSL

2).生成自签名的CA key和证书(简单起见客户端和服务端共用一个CA证书)

openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -subj "/CN=www.xxx.com" -out ca.pem

3).生成服务器端的key和证书

openssl genrsa -out server.key 2048

openssl req -new -key server.key -out server.csr -subj "/CN=127.0.0.1"

openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out server.pem -days 3650 -sha256

4).生成客户端key和证书

openssl genrsa -out client.key 2048

openssl req -new -key client.key -out client.csr -subj "/CN=127.0.0.1"

openssl x509 -req -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client.pem -days 3650 -sha256

EMQX 修改config文件

#单项向认证配置
listener.ssl.external.keyfile = etc/certs/server.key
listener.ssl.external.certfile = etc/certs/server.pem

在MQTT客户端
CA certs 只需要添加ca.pem

#双向认证配置
listener.ssl.external.keyfile = etc/certs/server.key
listener.ssl.external.certfile = etc/certs/server.pem
listener.ssl.external.cacertfile = etc/certs/ca.pem

开启双向认证

listener.ssl.external.verify = verify_peer

禁止单向认证

listener.ssl.external.fail_if_no_peer_cert = true

何为SSL/TLS单向认证,双向认证?
单向认证指的是只有一个对象校验对端的证书合法性。
通常都是client来校验服务器的合法性。那么client需要一个ca.crt,服务器需要server.crt,server.key
双向认证指的是相互校验,服务器需要校验每个client,client也需要校验服务器。
server 需要 server.key 、server.crt 、ca.crt
client 需要 client.key 、client.crt 、ca.crt

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值