以下问题为 阿里云 mqtt 使用过程中发现
一、首先贴出简单核心代码如下
client.on('connect', function () {
client.publish('test/clientE', '' + (Math.random() * 10).toFixed(2), {'qos': 2, 'retain': true}, function (err) {
if (err) {
console.log(err)
} else {
console.log('消息发送成功')
}
})
})
二、运行结果如下
三、结果分析
正常情况下连接上只会发送一条消息,但结果显然不是,于是我打开 Wireshark 进行抓包分析如下
四、原因分析
从上图中可以看到,客户端一直在连接服务器,导致一直出发 connect 事件,导致结果就是一直发布消息,并不是理想中的只
发布一条消息。
我看了 mqtt.js 中的 connect事件,如下
事件 ‘connect’
function (connack) {}
在成功(重新)连接时发出(即connack rc = 0)。
connack收到connack数据包。当clean连接选项为false且服务器具有连接选项的上一个会话时clientId,则
connack.sessionPresent标志为true。在这种情况下,您可能依赖于存储的会话,而不希望不为客户端发送订阅命令。
结论:看到这里我想可能存在重复的 clientId 连接。(就是存在两个客户端 clientId 相同,两个在打架,一直争同一连接,
导致一直重连,重复发布消息)
五、解决方法
1、使用 client 的 connected 属性进行判断,简单判断如下
exports.pubMsg = function (ms) {
if (!client.connected) {
client.on('connect', function () {
console.log('连接成功')
})
} else {
client.publish('test/clientE', ms, {'qos': 2}, function (err) {
if (err) {
console.log(err)
}
})
}
}
connected 判断是否已成功连接服务器
2、保证你的 clientId 全局唯一
Client ID 由两部分组成,组织形式为 @@@,GroupID 代表一类设备,会重复,则使用 DeviceID 保证实
例 Id 唯一,因为我做的测试,DeviceID 都是随便写的导致出现如上问题,如果正式用在生产环境,DeviceID 可以用物联网设
备的设备ID 代替,可以保证全局唯一,但还是有必要加上上面的方法一。