EMQX使用背景
之前开发IOT相关项目,如鸿蒙的数字管家,曾使用了华为的IOT云服务,它本质上就是一个MQTT服务器。
这次,因新项目私有化部署的需要,学习本地私有化部署一个MQTT服务器,发现国内的很多资料都使用的是这个EMQX,它有个开源版本支持私有化部署,启动以后还有个Web版本的Dashboard管理,便于使用。
https://docs.emqx.com/zh/emqx/latest/
快速部署
为了快速上手,于是采用最简单的docker容器部署的方式。
参考官网文档,运行以下命令启动 Docker 容器:
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:latest
然而,启动后的效果跟官网文档的不同,最起码的用户权限配置都没有。后来发现,是因为配置了阿里的镜像加速器,虽然用的是emqx/emqx:latest镜像,但通过docker inspect emqx/emqx:latest发现,这个镜像实际才是4.3.11,但docker hub上已经是5.6.8了。咨询阿里云,给出阿里云的镜像服务也受到无法继续访问dockerhub的影响,只能拉取早期的镜像版本了。https://help.aliyun.com/zh/acr/product-overview/product-change-acr-mirror-accelerator-function-adjustment-announcement
解决方案
使用官方的离线包下载和导入,参考[这里](wget https://www.emqx.com/zh/downloads/broker/5.8.6/emqx-5.8.6-docker-amd64.tar.gz)
# 下载 emqx-5.8.6-docker-amd64.tar.gz
wget https://www.emqx.com/zh/downloads/broker/5.8.6/emqx-5.8.6-docker-amd64.tar.gz
# 安装
docker load < emqx-5.8.6-docker-amd64.tar.gz
# 启动
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:5.8.6
访问Dashboard控制台
通过浏览器访问 http://localhost:18083/(localhost 可替换为您的实际 IP 地址)以访问 EMQX Dashboard 管理控制台,进行设备连接与相关指标监控管理。
默认用户名及密码:admin/public ,启动后会提示更改管理员密码。
端口说明
从docker启动命令来看,EMQX 容器暴露的端口及其用途如下:
1883 端口
MQTT 协议(非加密):标准的 MQTT 端口,用于客户端通过 TCP 进行非加密通信。适用于物联网设备等场景。
8883 端口
MQTT over SSL/TLS(加密):提供加密的 MQTT 通信,通过 TLS/SSL 保证数据传输的安全性。
8083 端口
WebSocket MQTT(非加密):支持通过 WebSocket 协议进行 MQTT 通信,适用于浏览器等基于 Web 的客户端(非加密)。
8084 端口
WebSocket MQTT over TLS(加密):通过 WebSocket 提供加密的 MQTT 通信(WSS),确保浏览器客户端的安全连接。
18083 端口
EMQX 管理控制台:提供 Web 界面用于监控和管理 EMQX 服务器,包括查看连接状态、配置规则引擎等。
权限配置
默认EMQX没有权限认证,任何工具都可直接连接。
建议使用最简单也最直接的账号密码登录的方式,即使用内置数据库进行密码认证
在 EMQX Dashboard 页面,点击左侧导航栏的访问控制 -> 认证,在随即打开的认证页面,单击创建,依次选择认证方式为 Password-Based,数据源为 Built-in Database,进入配置参数页签:
添加成功后,再添加对应的账号和密码。
客户端连接验证
- 桌面端客户端工具MQTTX:https://mqttx.app/zh/downloads
- 运行在浏览器上的 MQTT 5.0 WebSocket 客户端工具:https://mqttx.app/zh/web
进入容器使用命令
docker exec -u emqx -it emqx /bin/bash
# 成功进入容器后,可使用emqx命令
使用java代码订阅和发送
https://www.emqx.com/zh/blog/how-to-use-mqtt-in-java#%E5%9C%A8-java-%E4%B8%AD%E4%BD%BF%E7%94%A8-mqtt-5-0-%E5%8D%8F%E8%AE%AE
使用 MQTT 5.0 协议,需要将 Paho MQTT v5 依赖添加到 pom.xml 中:
<project>
...
<repositories>
<repository>
<id>Eclipse Paho Repository</id>
<url>https://repo.eclipse.org/content/repositories/paho-releases/</url>
</repository>
</repositories>
<dependencies>
...
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.mqttv5.client</artifactId>
<version>1.2.5</version>
</dependency>
</dependencies>
</project>
使用 MQTT 5.0 的完整代码如下 :
package io.emqx.mqtt.demo;
import org.eclipse.paho.mqttv5.client.IMqttToken;
import org.eclipse.paho.mqttv5.client.MqttCallback;
import org.eclipse.paho.mqttv5.client.MqttClient;
import org.eclipse.paho.mqttv5.client.MqttConnectionOptions;
import org.eclipse.paho.mqttv5.client.MqttDisconnectResponse;
import org.eclipse.paho.mqttv5.common.MqttException;
import org.eclipse.paho.mqttv5.common.MqttMessage;
import org.eclipse.paho.mqttv5.common.packet.MqttProperties;
public class JavaDemoMQTTV5 {
public static void main(String[] args) {
String broker = "tcp://broker.emqx.io:1883";
String clientId = "demo_client";
String topic = "topic/test";
int subQos = 1;
int pubQos = 1;
String msg = "Hello MQTT";
try {
MqttClient client = new MqttClient(broker, clientId);
MqttConnectionOptions options = new MqttConnectionOptions();
client.setCallback(new MqttCallback() {
public void connectComplete(boolean reconnect, String serverURI) {
System.out.println("connected to: " + serverURI);
}
public void disconnected(MqttDisconnectResponse disconnectResponse) {
System.out.println("disconnected: " + disconnectResponse.getReasonString());
}
public void deliveryComplete(IMqttToken token) {
System.out.println("deliveryComplete: " + token.isComplete());
}
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println("topic: " + topic);
System.out.println("qos: " + message.getQos());
System.out.println("message content: " + new String(message.getPayload()));
}
public void mqttErrorOccurred(MqttException exception) {
System.out.println("mqttErrorOccurred: " + exception.getMessage());
}
public void authPacketArrived(int reasonCode, MqttProperties properties) {
System.out.println("authPacketArrived");
}
});
client.connect(options);
client.subscribe(topic, subQos);
MqttMessage message = new MqttMessage(msg.getBytes());
message.setQos(pubQos);
client.publish(topic, message);
client.disconnect();
client.close();
} catch (MqttException e) {
e.printStackTrace();
}
}
}