Ubuntu Mosquitto broker websocket is not working - websocket

I'm new at IoT & MQTT communication protocol. I'm trying to connect my broker which runs at Amazon Ec2 from my Vue web app via Websockets. I have started mosquitto with:
root#ip-xxx-xx-xx-xx:~# mosquitto -c /etc/mosquitto/conf.d/default.conf
1618518468: mosquitto version 1.6.7 starting
1618518468: Config loaded from /etc/mosquitto/conf.d/default.conf.
1618518468: Opening ipv4 listen socket on port 1883.
1618518468: Opening ipv6 listen socket on port 1883.
1618518468: Opening websockets listen socket on port 9001.
/etc/mosquitto/conf.d/default.conf file contains:
listener 1883
protocol mqtt
allow_anonymous true
listener 9001
protocol websockets
allow_anonymous true
My test js file is:
var mqtt = require('mqtt');
var count =0;
var client = mqtt.connect("mqtt://xx.xxx.xxx.xxx",{clientId:"mqttjs01"});
console.log("connected flag " + client.connected);
//handle incoming messages
client.on('message',function(topic, message, packet){
console.log("message is "+ message);
console.log("topic is "+ topic);
});
client.on("connect",function(){
console.log("connected "+ client.connected);
})
//handle errors
client.on("error",function(error){
console.log("Can't connect" + error);
process.exit(1)});
//publish
function publish(topic,msg,options){
console.log("publishing",msg);
if (client.connected == true){
client.publish(topic,msg,options);
}
count+=1;
if (count==2) //ens script
clearTimeout(timer_id); //stop timer
client.end();
}
//////////////
var options={
retain:true,
qos:1};
var topic="acs";
var message="test message";
var topic_list=["topic2","topic3","topic4"];
var topic_o={"topic22":0,"topic33":1,"topic44":1};
console.log("subscribing to topics");
client.subscribe(topic,{qos:0}); //single topic
client.subscribe(topic_list,{qos:1}); //topic list
client.subscribe(topic_o); //object
var timer_id=setInterval(function(){publish(topic,message,options);},5000);
//notice this is printed even before we connect
console.log("end of script");
But I'm getting this error:
New client connected from 176.xxx.xxx.xx as mqttjs01 (p2, c1, k60).
1618518546: Socket error on client mqttjs01, disconnecting.
I have installed libwebsockets, I have tried with various mosquitto versions. Current version is: 1.6.7.
Is there any problem with my client or broker? How can I fix this?

At the end of the publish() function the if statement is missing enclosing braces so it doesn't do what you think it does.
function publish(topic,msg,options){
console.log("publishing",msg);
if (client.connected == true){
client.publish(topic,msg,options);
}
count+=1;
if (count==2) //ens script
clearTimeout(timer_id); //stop timer
client.end();
}
Lets fix the indentation so we can see more clearly.
function publish(topic,msg,options){
console.log("publishing",msg);
if (client.connected == true){
client.publish(topic,msg,options);
}
count+=1;
if (count==2) //ens script
clearTimeout(timer_id); //stop timer
client.end();
}
As you can see client.end() will ALWAYS be called when ever publish() is called. If you only want to publish twice you need to wrap the 2 statements in the braces (this is not python where whitespace has meaning)
if (count==2) { //ens script
clearTimeout(timer_id); //stop timer
client.end();
}
You really should indent all your code properly it will make it much easier to read and to spot errors like this.
Also as #JDAllen mentioned you are not making use of the WebSocket connection, unless this code is running in the browser, where the sandbox will force it to be a WebSocket connection even if you specify mqtt:// as the schema in the URL, and you will have to include the port number to make it actually connect. e.g.
ws://xxx.xxx.xxx.xxx:9001

Related

Is there a way to restart a queue in a specific logic

I have a daemon running, which I am using for a socket connection, is there any way to restart this daemon inside the code when a specific login applies. Any command? Restarting the daemon queue inside that queue
\Ratchet\Client\connect($this->stream)->then(function ($ws) {
$ws->on('message', function ($data) {
});
$ws->on('close', function ($code = null, $reason = null) {
//RESTART THE QUEUE THIS SOCKET BELONGS TO
Log::alert( "userData: WebSocket Connection closed! ({$code} - {$reason})" . PHP_EOL);
});
there are multiple sockets running (dispatching from the same job), and i want to restart all of them if one is closed

Not receiving payloads from mosquitto via websockets

I'm using a VPS and I'm sending data from my Arduino to the server via MQTT.
Mosquitto print payloads via terminal successfully but when I try to print it in real time via a web page nothing happens.
Knowing that I've already allowed websockets in Mosquitto conf, if I run :
sudo netstat -plnt
I get :
tcp 0 0 0.0.0.0:1883 0.0.0.0:* LISTEN
13248/mosquitto
tcp 0 0 0.0.0.0:1884 0.0.0.0:* LISTEN
20169/mosquitto
tcp6 0 0 :::1883 :::* LISTEN 13248/mosquitto
the topic I'm sending name : /pression and the code I'm using is:
<script>
var websocket="myserver.ovh.net";
var port= 1884;
var user="username";
var pass="password";
client = new Paho.MQTT.Client(websocket, port, "innovation");
// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
var options = {
useSSL: false,
userName: user,
password: pass,
onSuccess:onConnect,
onFailure:doFail
}
// connect the client
client.connect(options);
// called when the client connects
function onConnect() {
// Once a connection has been made, make a subscription and send a
message.
document.getElementById("connstatus").innerHTML = "Mqtt Connected";
console.log("Mqtt Connected");
client.subscribe("/pression");
}
function doFail(e){
console.log(e);
}
// called when the client loses its connection
function onConnectionLost(responseObject) {
document.getElementById("connstatus").innerHTML = "Mqtt Not Connected";
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
}
}
function onMessageArrived(message) {
console.log("Pression is :");
document.getElementById("connstatus").innerHTML = message.payloadString;
console.log(message.payloadString);
}
</script>
when I run the script it says "Mqtt Connected" than nothing happened.
However if I run in the terminal :
mosquitto_sub -t '/pression'
I get the pressure values.
if I keep the web page on for some minutes I get this message :
Mqtt Connected
test.html:76 onConnectionLost:AMQJS0008I Socket closed.
config file :
# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example
pid_file /var/run/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.log
include_dir /etc/mosquitto/conf.d
#password_file /etc/mosquitto/passwd
#allow_anonymous false
listener 1884
protocol websockets
mosquitto log :
1557922249: Config loaded from /etc/mosquitto/mosquitto.conf.
1557922249: Opening websockets listen socket on port 1884.
1557922254: New client connected from xx.xx.11.163 as innovation (c1, k60, u'innovation').
1557922279: Socket error on client innovation, disconnecting.
1557922279: New client connected from xx.xx.11.163 as innovation (c1, k60, u'innovation').
1557922318: Socket error on client innovation, disconnecting.
1557922318: New client connected from xx.xx.11.163 as innovation (c1, k60, u'innovation').
1557922346: Socket error on client innovation, disconnecting.
1557922346: New client connected from xx.xx.11.163 as innovation (c1, k60, u'innovation').
1557922363: Socket error on client innovation, disconnecting.
1557922364: New client connected from xx.xx.11.163 as innovation (c1, k60, u'innovation').
1557922463: Socket error on client innovation, disconnecting.
OK, the problem here is most likely that you are using a fixed client id (innovation) in the HTML.
You can only ever have 1 client connected with a given client id, so the broker will disconnect the oldest one when a new client with the same id connects (e.g. when you reload the page).
Try changing the connection line to something like this:
var clientID = "innovation_" + new Date().getTime();
client = new Paho.MQTT.Client(websocket, port, clientID);

Setting up ejabberd via websockets

I have an ejabberd server up and running.
I can test it via web clients and it works fine using BOSH connections.
I would like to connect to it via web sockets now, and I am not sure what I am missing for it to work, I just know it doesn't.
Here is an extract from my ejabberd.yml
hosts:
- "localhost"
- "somedomain.com"
- "im.somedomain.com"
listen :
port: 5280
ip: "::"
module: ejabberd_http
request_handlers:
"/websocket": ejabberd_http_ws
"/pub/archive": mod_http_fileserver
web_admin: true
http_bind: true
## register: true
## captcha: true
tls: true
certfile: "/etc/ejabberd/ejabberd.pem"
Now I tried to open a web socket via javascript as follows :
var ws = new WebSocket("ws://somedomain:5280/websocket/");
I get ERR_CONNECTION_TIMED_OUT in return. I have nothing within ejabberd's logs when I try to open a weksocket. I do have logs of the BOSH connections.
I am not sure if I am testing appropriately, nor if my server is setup correctly.
Any suggestion is most welcome.
Connection timeout error will throw by the server when the client does not send pong response to the server make sure you are sending the pong response.If you are using Strophe.js kindly check Handlers http://strophe.im/strophejs/doc/1.2.14/files/strophe-js.html#Strophe.Connection.addHandler
connection = new WebSocket("ws://somedomain:5280/websocket/");
//Adding ping handler using strophe connection
connection.addHandler(pingHandler, "urn:xmpp:ping", "iq", "get");
//Ping Handler Call back function
function pingHandler(ping) {
var pingId = ping.getAttribute("id");
var from = ping.getAttribute("from");
var to = ping.getAttribute("to");
var pong = strophe.$iq({
type: "result",
"to": from,
id: pingId,
"from": to
});
connection.send(pong);
return true;
}
Also, consider you are adding this configuration to your ejabberd.yml
websocket_ping_interval: 50
websocket_timeout: 60

How to listen to ACK packages on ephemeral ports

I need to write a tftp client implementation to send a file from a windows phone 8.1 to a piece of hardware.
Because I need to be able to support windows 8.1 I need to use the Windows.Networking.Sockets classes.
I'm able to send my Write request package but I am having troubles to receive the ack package (wireshark). This ack package is sent to an "ephemeral port" according to the TFTP specification but the port is blocked according to wireshark.
I know how to use sockets on a specific port but I don't know how to be able to receive ack packages send to different (ephemeral) ports. I need to use the port used for that ack package to continue the TFTP communication.
How would I be able to receive the ACK packages and continue to work on a different port? Do I need to bind the socket to multiple ports? I've been trying to find answers on the microsoft docs and google but other implementations gave me no luck so far.
As reference my current implementation:
try {
hostName = new Windows.Networking.HostName(currentIP);
} catch (error) {
WinJS.log && WinJS.log("Error: Invalid host name.", "sample", "error");
return;
}
socketsSample.clientSocket = new Windows.Networking.Sockets.DatagramSocket();
socketsSample.clientSocket.addEventListener("messagereceived", onMessageReceived);
socketsSample.clientSocket.bindEndpointAsync(new Windows.Networking.HostName(hostName), currentPort);
WinJS.log && WinJS.log("Client: connection started.", "sample", "status");
socketsSample.clientSocket.connectAsync(hostName, serviceName).done(function () {
WinJS.log && WinJS.log("Client: connection completed.", "sample", "status");
socketsSample.connected = true;
var remoteFile = "test.txt";
var tftpMode = Modes.Octet;
var sndBuffer = createRequestPacket(Opcodes.Write, remoteFile, tftpMode);
if (!socketsSample.clientDataWriter) {
socketsSample.clientDataWriter =
new Windows.Storage.Streams.DataWriter(socketsSample.clientSocket.outputStream);
}
var writer = socketsSample.clientDataWriter;
var reader;
var stream;
writer.writeBytes(sndBuffer);
// The call to store async sends the actual contents of the writer
// to the backing stream.
writer.storeAsync().then(function () {
// For the in-memory stream implementation we are using, the flushAsync call
// is superfluous, but other types of streams may require it.
return writer.flushAsync();
});
}, onError);
Finally found the issue.
Instead of connectAsynch I used getOutputStreamAsynch and now it receives messages on the client socket:
Some code:
tftpSocket.clientSocket.getOutputStreamAsync(new Windows.Networking.HostName(self.hostName), tftpSocket.serviceNameConnect).then(function (stream) {
console.log("Client: connection completed.", "sample", "status");
var writer = new Windows.Storage.Streams.DataWriter(stream); //use the stream that was created when calling getOutputStreamAsync
tftpSocket.clientDataWriter = writer; //keep the writer in case we need to close sockets we also close the writer
writer.writeBytes(sndBytes);
// The call to store async sends the actual contents of the writer
// to the backing stream.
writer.storeAsync().then(function () {
// For the in-memory stream implementation we are using, the flushAsync call
// is superfluous, but other types of streams may require it.
return writer.flushAsync();
});
}, self.onError);

Subscribing to a removed queue with spring-websocket and RabbitMQ broker (Queue NOT_FOUND)

I have a spring-websocket (4.1.6) application on Tomcat8 that uses a STOMP RabbitMQ (3.4.4) message broker for messaging. When a client (Chrome 47) starts the application, it subscribes to an endpoint creating a durable queue. When this client unsubscribes from the endpoint, the queue will be cleaned up by RabbitMQ after 30 seconds as defined in a custom made RabbitMQ policy. When I try to reconnect to an endpoint that has a queue that was cleaned up, I receive the following exception in the RabbitMQ logs: "NOT_FOUND - no queue 'position-updates-user9zm_szz9' in vhost '/'\n". I don't want to use an auto-delete queue since I have some reconnect logic in case the websocket connection dies.
This problem can be reproduced by adding the following code to the spring-websocket-portfolio github example.
In the container div in the index.html add:
<button class="btn" onclick="appModel.subscribe()">SUBSCRIBE</button>
<button class="btn" onclick="appModel.unsubscribe()">UNSUBSCRIBE</button>
In portfolio.js replace:
stompClient.subscribe("/user/queue/position-updates", function(message) {
with:
positionUpdates = stompClient.subscribe("/user/queue/position-updates", function(message) {
and also add the following:
self.unsubscribe = function() {
positionUpdates.unsubscribe();
}
self.subscribe = function() {
positionUpdates = stompClient.subscribe("/user/queue/position-updates", function(message) {
self.pushNotification("Position update " + message.body);
self.portfolio().updatePosition(JSON.parse(message.body));
});
}
Now you can reproduce the problem by:
Launch the application
click unsubscribe
delete the position-updates queue in the RabbitMQ console
click subscribe
Find the error message in the websocket frame via the chrome devtools and in the RabbitMQ logs.
reconnect logic in case the websocket connection dies.
and
no queue 'position-updates-user9zm_szz9' in vhost
Are fully different stories.
I'd suggest you implement "re-subscribe" logic in case of deleted queue.
Actually that is how STOMP works: it creates auto-deleted (generated) queue for the subscribe and yes, it is removed on the unsubscrire.
See more info in the RabbitMQ STOMP Adapter Manual.
From other side consider to subscribe to the existing AMQP queue:
To address existing queues created outside the STOMP adapter, destinations of the form /amq/queue/<name> can be used.
The problem is Stomp won't recreate the queue if it get's deleted by the RabbitMQ policy. I worked around it by creating the queue myself when the SessionSubscribeEvent is fired.
public void onApplicationEvent(AbstractSubProtocolEvent event) {
if (event instanceof SessionSubscribeEvent) {
MultiValueMap nativeHeaders = (MultiValueMap)event.getMessage().getHeaders().get("nativeHeaders");
List destination = (List)nativeHeaders.get("destination");
String queueName = ((String)destination.get(0)).substring("/queue/".length());
try {
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(queueName, true, false, false, null);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Resources