首页 > 解决方案 > 当我发布或接收消息时,Paho MQTT JS 客户端失去与 Mosquitto 代理的连接(错误 AMQJS0005E)

问题描述

前面的底线: Paho MQTT 客户端成功连接到我的 Mosquitto 代理,但当我尝试发布消息或收到来自它订阅的主题的消息时立即断开连接。我尝试过更改 Mosquitto 的侦听端口和身份验证设置,并使用两个不同版本的 Paho MQTT,但我仍然遇到同样的问题。

现在让我们详细介绍一下。

简介:我正在为一些通过 MQTT 通信的面部识别设备制作仪表板。我设置了一个 Mosquitto 代理,连接到它并使用 Python 的 Paho MQTT 客户端与设备通信没有问题(我制作了一种服务器来将设备的信息同步到数据库)。现在我正在制作网络界面,所以我添加了一个 WebSockets 侦听器,mosquitto.conf并使用 Paho MQTT 库为 Javascript 编写了一个脚本来连接它,订阅主题sgdrf/out,向主题发送简单的 JSON 消息以sgdrf/in获取在线列表设备,并在 Python 服务器到达后处理它的响应。

问题及尝试的解决方案:我运行Django服务器,加载网页并打开JS控制台,发现MQTT客户端成功连接到代理,但在尝试将消息发布到主题时立即断开连接sgdrf/in。这是控制台输出的每一行及其解释:

  1. onSuccess 函数产生的消息,表示客户端成功连接到 Mosquitto 代理:

    Conexión exitosa al 代理 MQTT。

  2. 在 onConnected 函数中,我添加console.log(uri)了查看客户端用于连接代理的 URI。我有:

    ws://localhost:61613/

  3. 打印uri到控制台后,我让客户端订阅sgdrf/out,然后将“订阅”打印到控制台:

    订阅

  4. 然后我调用get_online_devices(mqtt_client)一个函数,该函数创建一个简单的 JSON 字符串并将其发布到主题sgdrf/in。但首先,它将字符串打印到控制台,以便我可以检查它(以防万一):

    {"operator":"GetOnlineDevices","messageId":96792535859850080000,"info":{}}

  5. 然后,当publish方法实际执行时,是我得到这个错误的时候(由 onConnectionLost 函数捕获):

    Pérdida de conexión con el broker MQTT: AMQJS0005E 内部错误。错误消息:消息未定义,堆栈跟踪:没有可用的错误堆栈(código:5)

我检查了 Mosquitto 日志文件,它只说何时连接了新客户端,然后由于套接字错误而断开连接(每次重新加载页面时)。尾巴/var/log/mosquitto/mosquitto.log

1614796149: New connection from 127.0.0.1 on port 61612.
1614796149: New client connected from 127.0.0.1 as mqttx_53195902 (p2, c1, k60, u'admin').
1614796182: Socket error on client sgdrf_dashboard_8499, disconnecting.
1614796325: New client connected from ::ffff:127.0.0.1 as sgdrf_dashboard_1597 (p2, c1, k60, u'admin').
1614796325: Socket error on client sgdrf_dashboard_1597, disconnecting.
1614796336: New client connected from ::ffff:127.0.0.1 as sgdrf_dashboard_6565 (p2, c1, k60, u'admin').
1614796336: Socket error on client sgdrf_dashboard_6565, disconnecting.
1614796931: New client connected from ::ffff:127.0.0.1 as sgdrf_dashboard_9773 (p2, c1, k60, u'admin').
1614796931: Socket error on client sgdrf_dashboard_9773, disconnecting.
1614797168: Saving in-memory database to /var/lib/mosquitto/mosquitto.db.

我尝试更改中的侦听端口mosquitto.conf,并启用和禁用身份验证,但没有任何改变。显然,每次更改配置文件时,我都必须重新启动 Mosquito。我不认为问题出在蚊子身上。

无论我使用 Paho MQTT 1.1.0 版还是 1.0.3 版,我都有同样的问题。

作为一个实验,我在我的 Javascript 中注释掉了对的调用,get_online_devices这样它就不会尝试发布任何内容,重新加载页面并且没有错误,正如预期的那样。sgdrf/out然后,我使用 MQTTX 向MQTT JS 客户端订阅的主题发送 JSON 消息,它立即断开连接并显示相同的错误消息。

代码:在页面底部index.html

<!-- Paho MQTT -->
<script src="/static/js/paho-mqtt-min.js"></script>

<!-- Scripts -->
<script src="/static/js/dashboard.js"></script>
    
<script>
function get_online_devices(mqtt_client) {
    cmd = {
        operator: "GetOnlineDevices",
        messageId: generate_random_number_n_exp(20),
        info: {}
    };

    payload_string = JSON.stringify(cmd);
    console.log(payload_string)

    mqtt_client.publish("sgdrf/in", payload_string);
}

function add_device_to_list(device) {
    // Omitted for brevity. It's not being used yet.
}

let mqtt_client = make_mqtt_client("localhost", 61613);
let connection_options = make_connection_options(
    "admin",
    "CENSORED_PASSWORD"
);

mqtt_client.onConnected = function(reconnect, uri) {
    console.log(uri)
    mqtt_client.subscribe("sgdrf/out");
    console.log('subscribed');
    get_online_devices(mqtt_client);
};
mqtt_client.onConnectionLost = mqtt_client_on_connection_lost;
mqtt_client.onMessageDelivered = mqtt_client_on_message_delivered;

mqtt_client.onMessageArrived = function (msg) {
    // Omitted for brevity. Checks if the payload is a
    // JSON object with the right data and calls
    // add_device_to_list for each item of a list in it.
};

$(document).ready(function() {
    mqtt_client.connect(connection_options);

    $("#reload-device-list-btn").click(function() {
        get_online_devices(mqtt_client);
    });
});
</script>

上面提到的dashboard.js文件只是有一些我认为对其他页面有用的功能,所以我将它们分开到一个文件中:

// dashboard.js
function generate_random_number_n_exp(n) {
    return parseInt(Math.random() * Math.pow(10, n), 10)
}

function make_mqtt_client(host, port) {
    let client_id = "sgdrf_dashboard_" + generate_random_number_n_exp(4);
    return new Paho.Client(host, port, '/', client_id);
}

function make_connection_options(user, password) {
    let connection_options = {
        userName: user,
        password: password,
        onSuccess: mqtt_client_on_success,
        onFailure: mqtt_client_on_failure,
    };
    
    return connection_options;
}

function mqtt_client_on_success() {
    console.log('Conexión exitosa al broker MQTT.');
}

function mqtt_client_on_failure(error) {
    console.log(
        'Fallo de conexión con el broker MQTT: ' + error.errorMessage
        + ' (código: ' + error.errorCode + ')'
    );
}

function mqtt_client_on_connection_lost (error) {
    console.log('Pérdida de conexión con el broker MQTT: ' + error.errorMessage
        + ' (código: ' + error.errorCode + ')'
    );
}

function mqtt_client_on_message_delivered(msg) {
    let topic = message.destinationName;
    let payload = message.payloadString;
    console.log("Mensaje enviado a " + topic + ": " + payload);
}

function mqtt_client_on_message_arrived(msg) {
    let topic = message.destinationName;
    let payload = message.payloadString;
    console.log("Mensaje recibido de " + topic + ": " + payload);
}

这是我的mosquitto.conf文件的内容:

per_listener_settings true
listener 61612
allow_anonymous false
password_file /home/s8a/Projects/sgdrf/config/pwdfile.txt

listener 61613
protocol websockets
allow_anonymous false
password_file /home/s8a/Projects/sgdrf/config/pwdfile.txt

它只是设置了一个 TCP 侦听器和一个 WebSockets 侦听器,都不允许匿名连接,并使用 pwdfile 进行身份验证。正如我之前所说,我启用和禁用了匿名连接,并将端口号更改为 9001 并恢复为 61613,我仍然有同样的错误。

结论:我不知道该怎么办,这个项目的截止日期是下周。

标签: javascriptmqttmosquittopaho

解决方案


我觉得有点愚蠢,因为这确实是一个微不足道的打字错误。问题是 onMessageDelivered 和 onMessageArrived 函数有msg作为参数,但我message出于某种原因写在函数体中。这就是“消息未定义”错误的含义,message实际上是未定义的。无论如何,我修复了这个问题,现在它可以毫无问题地发送和接收消息。

...

更详细的故事:重要的是我是如何想出来的。

我决定弄脏我的手并打开非缩小版本的paho-mqtt.js. 我查找“无效错误”并找到错误常量的定义位置,以及在 catch 块中使用它的两个位置。在两个 catch 块中,我注意到有一个三元运算符检查(error.hasOwnProperty("stack") == "undefined")真假子句是否倒置,这就是为什么我得到“没有可用的错误堆栈”的原因。

所以我颠倒了这些条款,确实我在控制台中得到了一个堆栈跟踪(也许我应该尽可能地向 Paho 开发团队提交一份错误报告)。堆栈跟踪将我的mqtt_client_on_message_delivered函数放在顶部,所以我再次阅读它,突然一切都变得有意义了。然后我觉得浪费了一个下午在这件事上很愚蠢。


推荐阅读