简体   繁体   English

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

[英]Paho MQTT JS client loses connection to Mosquitto broker when I publish or receive message (error AMQJS0005E)

Bottom line up front: The Paho MQTT client sucessfully connects to my Mosquitto broker, but immediately disconnects when I try to publish a message or when it receives a message from a topic it's subscribed to.前面的底线: Paho MQTT 客户端成功连接到我的 Mosquitto 代理,但当我尝试发布消息或收到来自它订阅的主题的消息时立即断开连接。 I've tried changing Mosquitto's listening port and authentication settings, and using two different versions of Paho MQTT, and I still have the same problem.我尝试过更改 Mosquitto 的侦听端口和身份验证设置,并使用两个不同版本的 Paho MQTT,但我仍然遇到同样的问题。

Now let's get into detail.现在让我们详细介绍一下。

Intro: I'm making a dashboard for some facial recognition devices that communicate through MQTT.简介:我正在为一些通过 MQTT 通信的面部识别设备制作仪表板。 I set up a Mosquitto broker and I've had no problems connecting to it and communicating with the devices using the Paho MQTT client for Python (I made a kind of server to sync the device's info to a database).我设置了一个 Mosquitto 代理,连接到它并使用 Python 的 Paho MQTT 客户端与设备通信没有问题(我制作了一种服务器来将设备的信息同步到数据库)。 Now I'm making the web interface, so I added a WebSockets listener to my mosquitto.conf and wrote a script using the Paho MQTT library for Javascript to connect to it, subscribe to topic sgdrf/out , send a simple JSON message to topic sgdrf/in to get the list of online devices, and process the response of the Python server once it arrives. Now I'm making the web interface, so I added a WebSockets listener to my mosquitto.conf and wrote a script using the Paho MQTT library for Javascript to connect to it, subscribe to topic sgdrf/out , send a simple JSON message to topic sgdrf/in获取在线设备列表,并处理Python服务器到达后的响应。

Problem and attempted solutions: I ran the Django server, loaded the web page and opened the JS console to find that the MQTT client successfully connected to the broker but immediately disconnected when it tried to publish the message to topic sgdrf/in .问题及尝试解决方法:我运行Django服务器,加载web页面,打开JS控制台发现MQTT客户端成功连接到broker,但是当它试图将消息发布到主题sgdrf/in时立即断开连接。 Here's each line of console output with their explanations:这是控制台 output 的每一行及其解释:

  1. The message produced by the onSuccess function, which indicates that the client successfully connected to the Mosquitto broker: onSuccess function 产生的消息,表示客户端成功连接到 Mosquitto 代理:

    Conexión exitosa al broker MQTT. Conexión exitosa al 代理 MQTT。

  2. In the onConnected function, I added console.log(uri) to see the URI used by the client to connect to the broker.在onConnected function中,我添加了console.log(uri)来查看客户端连接broker使用的URI。 I got:我有:

    ws://localhost:61613/ ws://localhost:61613/

  3. After printing uri to console, I made the client subscribe to sgdrf/out and then print 'subscribed' to console:uri打印到控制台后,我让客户端订阅sgdrf/out ,然后将“订阅”打印到控制台:

    subscribed订阅

  4. Then I call get_online_devices(mqtt_client) , a function which creates a simple JSON string and publishes it to the topic sgdrf/in .然后我调用get_online_devices(mqtt_client) ,一个 function ,它创建一个简单的 JSON 字符串并将其发布到主题sgdrf/in But first, it prints the strign to the console so that I can check it (just in case):但首先,它将字符串打印到控制台,以便我可以检查它(以防万一):

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

  5. Then, when the publish method is actually executed, is when I get this error (captured by the onConnectionLost function):然后,当实际执行publish方法时,是我收到此错误(由 onConnectionLost 函数捕获):

    Pérdida de conexión con el broker MQTT: AMQJS0005E Internal error. Pérdida de conexión con el broker MQTT: AMQJS0005E 内部错误。 Error Message: message is not defined, Stack trace: No Error Stack Available (código: 5)错误消息:消息未定义,堆栈跟踪:没有可用的错误堆栈(código:5)

I checked the Mosquitto log file and it only says when a new client was connected and then when it was disconnected because of a socket error (each time for every page reload).我检查了 Mosquitto 日志文件,它只说何时连接了新客户端,然后由于套接字错误而断开连接(每次重新加载页面时)。 Tail of /var/log/mosquitto/mosquitto.log : /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.

I tried changing the listening port in mosquitto.conf , and enabling and disabling authentication, but it changes nothing.我尝试更改mosquitto.conf中的侦听端口,并启用和禁用身份验证,但它没有任何改变。 And obviously I've had to restart Mosquito every time I changed the config file.显然,每次更改配置文件时,我都必须重新启动 Mosquito。 I don't think the problem is Mosquitto.我不认为问题出在蚊子身上。

I have the same problem whether I use Paho MQTT version 1.1.0 or 1.0.3.无论我使用 Paho MQTT 1.1.0 版还是 1.0.3 版,我都有同样的问题。

As an experiment, I commented out the call to get_online_devices in my Javascript so that it doesn't try to publish anything, reloaded the page and there was no error, as expected.作为一个实验,我在我的 Javascript 中注释掉了对get_online_devices的调用,这样它就不会尝试发布任何内容,重新加载页面并且没有错误,正如预期的那样。 Then, I used MQTTX to send a JSON message to the sgdrf/out topic to which the MQTT JS client is subscribed to, and it immediately disconnected with the same error message.然后,我使用 MQTTX 向 MQTT JS 客户端订阅的sgdrf/out主题发送了一条 JSON 消息,它立即断开连接并显示相同的错误消息。

Code: At the bottom of the page ( index.html ) I have the following code (the original code has Django template tags to fill in some values, so this is the actual code received by the browser):代码:在页面底部( index.html )我有如下代码(原代码有Django模板标签填写一些值,所以这是浏览器收到的实际代码):

<!-- 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>

The dashboard.js files mentioned above just has some functions that I think will be useful for other pages, so I separated them to a file:上面提到的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);
}

Here are the contents of my mosquitto.conf file:这是我的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

It just sets up a TCP listener and a WebSockets listener, both disallow anonymous connections, and authenticate using a pwdfile.它只是设置了一个 TCP 监听器和一个 WebSockets 监听器,都不允许匿名连接,并使用 pwdfile 进行身份验证。 As I said before, I have enabled and disabled anonymous connections, and changed the port number to 9001 and back to 61613, and I still have the same error.正如我之前所说,我启用和禁用了匿名连接,并将端口号更改为 9001 并恢复为 61613,我仍然有同样的错误。

Conclusion: I don't know what to do and this project's deadline is next week.结论:我不知道该怎么办,这个项目的截止日期是下周。

I feel kinda stupid, because it was really a trivial typing mistake.我觉得有点愚蠢,因为这确实是一个微不足道的打字错误。 The problem is that the onMessageDelivered and onMessageArrived functions have msg as argument, but I wrote message in the function body for some reason.问题是 onMessageDelivered 和 onMessageArrived 函数有msg作为参数,但我出于某种原因在 function 正文中写了message That's what the "message is not defined" error meant, message is literally not defined.这就是“消息未定义”错误的含义, message实际上未定义。 Anyway I fixed that and now it sends and receives messages without problems.无论如何,我修复了这个问题,现在它可以毫无问题地发送和接收消息。

... ...

More detailed story: What was not trivial is how I figured it out.更详细的故事:重要的是我是如何想出来的。

I decided to get my hands dirty and opened the non-minified version of paho-mqtt.js .我决定亲自动手并打开paho-mqtt.js的非缩小版本。 I looked for "Invalid error" and found where the error constant is defined, and two places where it's used in a catch block.我查找“无效错误”并找到错误常量的定义位置,以及在 catch 块中使用它的两个位置。 In both catch blocks I noticed that there was a ternary operator checking if (error.hasOwnProperty("stack") == "undefined") but the true and false clauses were inverted, which is why I was getting "No Error Stack Available".在两个 catch 块中,我注意到有一个三元运算符检查 if (error.hasOwnProperty("stack") == "undefined")但是真假子句被颠倒了,这就是为什么我得到“没有可用的错误堆栈” .

So I inverted the clauses, and indeed I got a stack trace in the console (maybe I should file a bug report to the Paho dev team when I can).所以我颠倒了这些条款,确实我在控制台中得到了一个堆栈跟踪(也许我应该尽可能地向 Paho 开发团队提交一份错误报告)。 The stack trace had my mqtt_client_on_message_delivered function right at the top, so I read it again and suddenly everything made sense.堆栈跟踪的顶部有我的mqtt_client_on_message_delivered function,所以我再次阅读它,突然一切都变得有意义了。 Then I felt stupid for wasting an afternoon on this.然后我觉得浪费了一个下午在这件事上很愚蠢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM