作者:赖尧
一、mqtt协议介绍
MQTT(Message Queuing Telemetry Transport)是一种轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境。它在物联网应用中广受欢迎,能够实现传感器、执行器和其它设备之间的高效通信。
二、MQTT协议实现方式
实现MQTT协议需要客户端和服务器端通讯完成,在通讯过程中,MQTT协议中有三种身份:发布者 (Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消 息代理是服务器,消息发布者可以同时是订阅者。
MQTT传输的消息分为:主题(Topic)和负载(payload)两部分:
三、使用ohos_mqtt客户端插件
下载安装
1. 客户端封装 mqttClient.ts
// @ts-ignore
import { MqttAsync } from '@ohos/native_mqtt'
import {
Client,
MqttClientOptions,
MqttConnectOptions,
MqttPublishOptions,
MqttSubscribeOptions,
MqttResponse,
MqttMessage,
QoS
// @ts-ignore
} from '@ohos/native_mqtt/src/main/ets/components/MainPage/MqttOption'
import { ThreadWorkerGlobalScope } from '@ohos.worker'
// import { platformTopics } from '../configs/mqttConfig'
import Log from '../utils/Logger'
import { sleep } from '../utils'
const TAG: string = '@MqttClient@';
class MqttClient {
private mqClient: Client;
private baseTopic: string;
public workerPort: ThreadWorkerGlobalScope;
static getInstance() {
if (!globalThis.mqttClient) {
Log.info(TAG, 'new MqttClient');
globalThis.mqttClient = new MqttClient();
}
return globalThis.mqttClient;
}
init(productId: string, deviceId: string, workerPort: ThreadWorkerGlobalScope) {
this.workerPort = workerPort;
this.baseTopic = `/v1/${ productId }/${ deviceId }/`
Log.info(TAG, 'baseTopic: ' + this.baseTopic);
}
async createAndConnect(clientOptions: MqttClientOptions, connectOptions: MqttConnectOptions): Promise<void> {
return new Promise(async (resolve, reject) => {
try {
Log.info(TAG, 'mqtt create!');
// 创建mqtt客户端
this.mqClient = MqttAsync.createMqtt(clientOptions);
Log.info(TAG, 'mqtt start connecting...');
// 连接mqtt服务
while(true) {
const connectState = await this.connect(connectOptions);
if (connectState) {
break;
}
Log.info(TAG, 'connectState: ' + connectState);
await sleep(20 * 1000);
Log.info(TAG, 'reconnection');
}
this.messageArrived();
// 订阅平台下发的所有topic
// await Promise.all(platformTopics.map(v => this.subscribe(`${ this.baseTopic }${ v }`)));
resolve();
this.connectLost();
} catch (err) {
Log.error(TAG, 'createAndConnect err: ' + JSON.stringify(err));
}
});
}
// 连接mqtt
async connect(connectOptions) {
return new Promise(async (resolve, reject) => {
try {
const data: MqttResponse = await this.mqClient.connect(connectOptions);
Log.info(TAG, 'mqtt connect data: ' + JSON.stringify(data));
if (data.code !== 0) {
resolve(false);
return Log.error(TAG, 'mqtt connect fail: err: ' + JSON.stringify(data));
}
Log.info(TAG, 'mqtt connect success!');
resolve(true);
} catch (err) {
Log.error(TAG, 'connect err: ' + JSON.stringify(err));
resolve(false);
}
});
}
// 订阅消息
public subscribe(topic: string, qos: QoS = 1): Promise<void> {
Log.info(TAG, 'mqtt subscribe topic: ' + topic);
const subscribeOption: MqttSubscribeOptions = { topic, qos };
return new Promise((resolve, reject) => {
this.mqClient.subscribe(subscribeOption, (err: Error, data: MqttResponse) => {
Log.info(TAG, 'mqtt subscribe data: ' + JSON.stringify(data));
if (err || data.code !== 0) {
reject(err || data);
return Log.info(TAG, 'mqtt subscribe error: ' + err);
}
resolve();
});
});
}
// 取消订阅
public unsubscribe<T>(topic: string, qos: QoS = 1): void {
const subscribeOption: MqttSubscribeOptions = { topic, qos };
this.mqClient.unsubscribe(subscribeOption, (err, data: MqttResponse) => {
if (err) return Log.error(TAG, 'mqtt unsubscribe error: ' + err);
Log.info(TAG, 'mqtt unsubscribe data: ' + JSON.stringify(data));
});
}
// 接收消息
public messageArrived(): void {
this.mqClient.messageArrived((err: Error, data: MqttMessage) => {
if (err) return Log.error(TAG, 'mqtt messageArrived error: ' + err);
// 接收消息, 有时候会出现乱码问题, 解决字符串乱码
const index = data.payload.lastIndexOf('}');
data.payload = data.payload.substring(0, index + 1);
Log.info(TAG, 'mqtt messageArrived data: ' + JSON.stringify(data));
this.workerPort.postMessage({
key: 'MqttMessageArrived',
params: [data]
});
});
}
// 发布消息
async publish<T>(topic: string, payload: string | Record<string, any>, qos: QoS = 0): Promise<MqttResponse> {
if (typeof payload !== 'string') {
payload = JSON.stringify(payload);
}
topic = `${this.baseTopic}${topic}`;
const publishOption: MqttPublishOptions = { topic, payload, qos, retained: false };
const connectState = await this.mqClient.isConnected();
Log.info(TAG, 'mqtt connectState: ' + connectState);
if (!connectState) {
this.reconnect();
return
}
Log.info(TAG, 'publishOption: ' + JSON.stringify(publishOption));
return this.mqClient.publish(publishOption)
}
// 断开连接
public disconnect(): void {
this.mqClient.disconnect((err: Error, data: MqttResponse) => {
if (err) return Log.error(TAG, 'mqtt disconnect error: ' + JSON.stringify(err));
Log.info(TAG, 'mqtt disconnect data: ' + JSON.stringify(data));
});
}
// 连接丢失监听
public connectLost(): void {
this.mqClient.connectLost((err: Error, data: MqttResponse) => {
if (err) return Log.error(TAG, 'mqtt connectLost error: ' + JSON.stringify(err));
Log.info(TAG, 'mqtt connectLost data: ' + JSON.stringify(data));
this.reconnect();
})
}
// 重连
async reconnect(): Promise<boolean> {
let isReConnected: boolean = await this.mqClient.reconnect();
Log.info(TAG, 'isReConnected state: ' + isReConnected);
// 注意: 重链订阅平台下发的所有topic
await Promise.all(platformTopics.map(v => this.subscribe(`${ this.baseTopic }${ v }`)));
return isReConnected;
}
// 销毁mqtt客户端
public destroy(): void {
Log.info(TAG, 'mqtt destroy');
this.mqClient && this.mqClient.destroy();
}
}
const mqttClient = MqttClient.getInstance();
export default mqttClient;
- 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.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
2. mqqt客户调用
mqtt客户端调用是在worker线程下, 为了减少主线程计算压力;
mqttClientWorker.ts
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。