Hello I'm new to all this IOT thing and I want to be able to send and receive data from an Arduino via mqtt using https://myqtthub.com as our broker. I used the following code in order to connect:
import React, { Component } from 'react';
var mqtt = require('mqtt');
var options={
clientId:"mqttjs01",
username:"user",
password:"password",
clean:true};
var client = mqtt.connect("mqtt://node02.myqtthub.com",options)
client.on('connect', () => {
alert('Connected!');
console.log('Connected');
});
class Garage extends Component {
render() {
return (
<div>
<h1>HEllooo</h1>
</div>
);
}
}
export default Garage;
I'm having the error:
"WebSocket connection to 'ws://node02.myqtthub.com/' failed: Error during WebSocket handshake: Unexpected response code: 301"
Any help will be appreciated.
Assuming this is all running in the browser (mainly because MQTT.js is forcing the connection to be over ws:// as that is the ONLY option in the browser).
Looking at the docs for myqtthub, they do NOT claim any support for MQTT over Websockets (and the support forum says they don't support it yet). This means your application will NOT work with this broker provider until they add Websockets support..
Ugh....Where to start....
First off, go read the docs at https://github.com/mqttjs/MQTT.js
You CONNECT, but you never SUBSCRIBE...not to mention you didn't post any code that you are PUBLISHing any data. Your client can both send (PUBLISH) and receive (SUBSCRIBE) data, but you have to set them both up.
As for your initial problem, you didn't define the port to use on the connect. You are also specifying mqtt:// as the protocol, not ws://, so that will also cause you problems if you really do want a WebSocket connection. How you are getting that websocket error is a mystery, since your code example shows it to be using the MQTT protocol.
If you are just starting out, stick with mqtt:// and work up from that.
Related
I was trying to implement web-sockets (npm ws) in my express application, but got stuck on how I should implement my websockets so that they work with express router.
Currently, my endpoints look like this...
router.post('/create-note', jwtAuthentication, NotesController.createNote);
router.get('/get-notes/:id',jwtAuthentication, NotesController.getUserNotes);
router.??('/socket-endpoint', NotesController.wssNote);
As you can see, I am unsure of what method to call on my router. I have tried using 'get' and 'post, but for some reason it only works after I try a second connection on postman. (I click connect, nothing happens, I then click disconnect and connect again and it works.)
I know that I can pass in the path when creating the WebSocketServer...
var wss = new WebSocketServer({server: server, path: "/hereIsWS"});
This does work, but if it is possible to use routers with web-sockets, I think it would make my whole project much cleaner and more organised.
I have come across people recommending 'express-ws', but was wondering if there was a better method to solve my problem, specifically a method that does not involve other packages.
Thanks in advance!
You do not use Express routers with webSockets. That's not the proper architecture for webSockets. Your webSocket server can share an http server with Express, but that's pretty much all the two have to do with one another.
webSockets connect on a particular path which you pass to the webSocketServer() constructor as it appears you already know. Once they are connected they stay connected and form a TCP pipe that you can send packets of data from client to server or from server to client. There is no Express routing used for that.
You can create your own message handling within a webSocket message by creating a message name as part of the webSocket payload if you want (this is something that the socket.io layer on top of webSockets does for you), but it has nothing to do with Express at that point. That's just in how you choose to handle the incoming webSocket packets.
if there was a better method to solve my problem
What is your specific problem? Perhaps if you stated the specific problem you want help with, we could provide further assistance.
To handle incoming webSocket messages, you can follow the example in the ws server doc:
wss.on('connection', function connection(ws) {
ws.on('message', function message(data) {
console.log('received: %s', data);
});
ws.send('something');
});
To further break up this to handle different types of incoming webSocket messages, you have to create your own message format that you can branch on or use socket.io instead on both client and server that does that for you.
I'm using socket.io and socket.io-client on the Express and React sides, respectively.
On the server side, I console.log in the connection event with the socket.id, and it always displays two connections when I only have one page open, like so:
A user connected woF_Gu_8ElqMB7a5AAAC
A user connected lBAycJ6j0X5Q469SAAAD
However, when emitting messages from the front end, only one connection is used.
Here's how I set up socket.io server side:
// ** bin/www file **
var server = http.createServer(app);
const io = require('socket.io')(server);
// Get socket module and pass it the io socket from here
require('../sockets')(io);
// ** sockets.js **
module.exports = io => {
io.on('connection', (socket) => {
console.log("A user connected", socket.id); // Fires twice with different IDs
socket.on("Setup", data => {
console.log("Data received:", data); // Only fires once per emit from frontend
}
socket.on("disconnect", () => {
console.log("User disconnected");
}
}
Here's how I set up client side, though I'm not sure this matters since it's happening consistently even when I don't have this code in:
import io from 'socket.io-client';
const socket = io(window.location.origin);
Any idea why I'm getting two connections all the time? Thanks!
EDIT: Adding network screenshot.
I solved my problem and wanted to share the solution here though I don't know exactly why what I was doing previously wasn't working.
I was using React Router in App.js, and I was importing socket.io-client in a component that got routed to. That was giving a double-connection for some reason (or more, depending on where I put the const socket = io(); line).
My solution was to import socket.io-client in App.js and pass io to the component as a prop where needed, like so:
import * as io from 'socket.io-client';
const socket = io();
class App extends Component {
render() {
return (
<Router>
<Header/>
<Switch>
<Route exact path="/" render={props => (<Home/>)}/>
<Route exact path="/story" render={props => (<Start socket={socket} />)}/>
</Switch>
</Router>
);
}
}
export default App;
This defines the socket at a high level and passes down where needed, so nothing is getting called twice and I stay at one connection.
OK, let's analyze your network trace in the screenshot. I'll start at the line that says "localhost" because that is presumably where you reloaded a page.
localhost - Normal reload of a cached page
8 script files requested - All load normally
Two socket.io requests arrive that are ?EIO=3&transport=polling&t=N6pOEHc. These are not normal requests. They are missing an sid=xxxxx value from the URL.
A socket.io request arrives that is ?EIO=3&transport=polling&t=N6pOEKbsid=zhaGN0gOV6Qh3bg-AAAq. These look a normal socket.io connection initiation with a few polling requests before it switches over to a webSocket.
A fetch Ajax request for incomplete arrives.
A second socket.io polling request on the sid=zhaGN0gOV6Qh3bg-AAAq arrives. This again looks normal.
A new socket.io request arrives from ?EIO=3transport=polling&t=N6pOEPQ&sid=wWH-VzFditNgmdWNAAAr. This is the second normal looking socket.io connection request. But, we don't know why there is a second attempt to connect.
A webSocket connection sent out to socketjs-node and accepted (101 status) as a webSocket connection.
Another socket.io polling request sent by sid=zhaGN0gOV6Qh3bg-AAAq. This is probably a request to convert to a webSocket connection, but is still marked as "pending" so it apparently did not succeed (as of the screenshot, perhaps never).
Another polling request on the second socket.io connection sid=wWH-VzFditNgmdWNAAAr
manifest.json and favicon.ico are requests
4 more polling requests from the second connection &sid=wWH-VzFditNgmdWNAAAr.
2 more polling requests from the first connection sid=zhaGN0gOV6Qh3bg-AAAq which definitely indicates that the previous attempt to turn this into a webSocket apparently did not work.
So, there are actually three socket.io attempts here. The first one looks a bit mal-formed, not sure why that is. The second two look like they are both initiated by client code. Neither one of them succeeds in switching to the webSocket transport.
My best guess would be that you have mismatched socket.io versions in client and server and thus they are having a hard time making the right type of lasting connection. It could also be that there's some sort of infrastructure in the way like a proxy that is preventing a webSocket connection from succeeding.
For other possible reasons, see this: Whats the problem with the socketio connection?
Another thing you can do for debugging purposes is to change the client code from this:
io(window.location.origin);
to this:
io(window.location.origin, {transports: ['websocket']});
This will force this connection attempt to ONLY connect with a webSocket. If we see a network trace from this, we can more clearly see whether a webSocket connection succeeds of fails.
It is also unusual to be using window.location.origin as the URL. If you just leave the URL out entirely, socket.io will just connect back to the host of the page which is generally what you want.
Use Socket.once("connected") View the doc https://socket.io/docs/v4/listening-to-events/
I am writing a very simple nodejs socket.io app. Somehow this returns "can't set headers after they are sent" error. but I can't see the point where the header is set again. I've only called server.listen once and I believe socket.listen works independently so it shouldn't conflict.
I am aware that can't set headers error had been posted a multiple times. I've read them briefly and I also understand how does response.writeHead works under normal circumstances(I've experimented with some node.js apps with response.writeHead, they worked fine most cases) it seems I am missing something from here. is it due to socket.io?
const fs = require("fs");
const server = require("http").createServer();
const io = require("socket.io").listen(server);
server.listen(52273,function(){
console.log("server up");
});
server.on("request",function(request,response){
fs.readFile("mainpage.html",function(error,data){
response.writeHead(200,{"Content-Type":"text/html"});
response.end(data);
});
});
io.sockets.on("connection",function(socket){
var roomName = null;
socket.on("join", function(data){
roomName = data;
socket.join(data);
console.log("client joined" + data);
});
socket.on("message",function(data){
io.sockets.in(roomName).emit("message","test");
});
});
It probably helps a bit here to understand a little bit about how socket.io works with your web server. socket.io uses the webSocket protocol as it's base protocol. A webSocket connection starts with an HTTP request that has special header set in it to indicate the start of a webSocket connection. A properly functioning web server will see this webSocket header and turn the request over to the webSocket handler to initiate the webSocket connection.
But, this handler you have:
server.on("request",function(request,response){
fs.readFile("mainpage.html",function(error,data){
response.writeHead(200,{"Content-Type":"text/html"});
response.end(data);
});
});
Looks like it is responding to every single request that arrives and sending a response, no matter what the request was. So, I can imagine that when the webSocket request comes in you're sending two responses, one from the webSocket server code and one from your request handler above.
Probably, you need to be able to only send your mainpage.html response for particular URLs that are not your webSocket request.
To see a little more about what's going in, insert a console.log() into here:
server.on("request",function(request,response){
console.log(request.url);
fs.readFile("mainpage.html",function(error,data){
response.writeHead(200,{"Content-Type":"text/html"});
response.end(data);
});
});
And, you will probably see you are sending your mainpage.html to a webSocket request which is not what you want to do. You will likely want to add some if logic so that your request handler is avoiding the webSocket requests.
What version of Node you using?
We had the same problem when we were using 0.9.x. I downgraded Node to 0.8.4 and the problem seems to have gone away.
My best guess is something in Node has changed that Socket.io doesnt agree with.
Thanks everyone. I've solved problem by installing express to my experiment app. I've read the manual again and discovered the socket.io v2 is now requiring express app as a dependency. It seems I have been using socket.io v2 but somehow sticked to socket.io v1 style app writing. It also worked when I downgraded it to socket.io v1.
TL;DR - socket.io v2 is not compatible with apps written for socket.io v1. When a socket.io app returns "can't set headers after they are sent" errors, try use proper version of the socket.io or install correct dependencies.
OK this is very simple to anyone who's used websocket and nodejs.
I have created a websocket server named ws_server.js and put it in C:\Program Files (x86)\nodejs where I have installed the nodejs framework. I started the server and it is running and it says it's listening on port 8080. So far so good, I have the server running.
Now I simply want to connect to it from client code so that I can do all that lovely stuff about capturing events using event listeners etc. The problem is, embarassingly, I cannot figure out what URL to use to connect to my websocket server.
function init() {
testWebSocket();
}
function testWebSocket() {
websocket = new WebSocket("ws://localhost:8080/"); // WHAT URL SHOULD BE USED HERE?
websocket.onopen = function(evt) { alert("OPEN") };
websocket.onclose = function(evt) { alert("CLOSE") };
websocket.onmessage = function(evt) { alert("MESSAGE") };
websocket.onerror = function(evt) { alert("ERROR") };
}
function doSend(message) {
// this would be called by user pressing a button somewhere
websocket.send(message);
alert("SENT");
}
window.addEventListener("load", init, false);
When I use ws://localhost:8080 the only events that trigger are CLOSE and ERROR. I cannot get the client to connect. I must be missing something very simple. Do I need to set up my nodejs folder in IIS for example and then use that as the URL?
Just to reiterate, the websocket server is running fine, I just don't know what URL to use to connect to it from the client.
EDIT: The websocket server reports the following error.
Specified protocol was not requested by the client.
I think I have got it working by doing the following.
var websocket = new WebSocket("ws://localhost:8080/","echo-protocol");
The problem being that I needed to specify a protocol. At least now I get the onopen event. ...if nothing much else
I was seeing the same error, the entire web server goes down. Adding the protocol fixes it but leaves me wondering why it was implemented this way. I mean, one bad request should not bring down your server.
You definitely have to encase it a try/catch, but the example code provided here https://www.npmjs.com/package/websocket (2019-08-07) does not. This issue can be easily avoided.
I just wanted to share a crazy issue that I had. I was able to connect to a websocket of an old version of a 3rd party app in one computer, but not to a newer version of the app in another.
Moreever, even in new computer with the new version of the app, The app was able to connect to the websocket, but no matter what I did, when I tried to connect with my own code, I kept getting the error message that the websocket connection failed
Long story short, They changed an apache configuration that allowed connecting to the websocket via a proxy.
In the old version, apache config was:
ProxyPass /socket/ ws://localhost:33015/ retry=10
ProxyPass /socket ws://localhost:33015/ retry=10
In the new version, apache config was changed to:
ProxyPass /socket/ ws://localhost:33015/ retry=10
By bad luck, I was trying to connect to ws://localhost/socket and not to ws://localhost/socket/. As a result, proxy was not found, and connection returned an error.
Moral of the story: Make sure that you are trying to connect to a websocket url that exists.
For me, the solution was to change the URL from ws:// to wss://. This is because the server I was connecting to had updated its security, and now only accepted wss.
Trying to use socket.io-client to connect to a websocket server that is written in Go. I've successfully connected using the node WebSocket library (npm). So the working Websocket code looks like:
goSocketPort = 6060
url = "ws://localhost:#{goSocketPort}/streamresults/"
ws = new WebSocket(url)
ws.on('open', ->
log "socket opened"
)
ws.on('message', (message) ->
console.log('received: %s', message)
#log "Socket message: #{JSON.stringify message}"
)
Pretty easy and it works -- the socket on the other end sends messages on a set frequency. But I initially tried with socket.io-client (npm) and just couldn't get it to go. It certainly lists websocket as its first-preference transport, but damn if I can get it to connect:
socket = ioClient.connect("#{url}", {port: goSocketPort, transports: ['xhr-polling', 'websocket']})
socket.on("connect", (r) ->
log "connected to #{url}"
)
The connection never happens, so none of the on events are fired and the code exits right away. I've tried: leaving the port off the url and adding it in the options, leaving off the transports option (which means "all" according to the docs) and using an http url. Is socket-io.client not capable of connecting to a "standard" websocket?
Based on our chat, it looks like you were misled by this quote:
The socket.io client is basically a simple HTTP Socket interface implementation. It looks similar to WebSocket while providing additional features and leveraging other transports when WebSocket is not supported by the user's browser.
What this means is that it looks similar to WebSocket from the perspective of client/server code that interacts with the Socket.io client/server. However, the network traffic looks very different from a simple WebSocket - there's an initial handshake in addition to a more robust protocol built on top of WebSocket once that's connected. The handshake is described here and the message protocol here (both are links to the Socket.IO protocol spec).
If you're writing a WebSocket server, you're better off just using the bare WebSocket interface rather than the Socket.io client, unless you intend to implement all of the Socket.io protocol.
Not sure if this was the case at the time, but socket.io's website now states this directly in the docs.
Although Socket.IO indeed uses WebSocket as a transport when possible,
it adds additional metadata to each packet. That is why a WebSocket
client will not be able to successfully connect to a Socket.IO server,
and a Socket.IO client will not be able to connect to a plain
WebSocket server either.
https://socket.io/docs/