NodeJS WebSocket Server on 'message' doesn't work - javascript

I am learning web socket in JS and trying to make simpliest chat app. I dont know why, but on message event doesn't work for server socket.
Can you explain whats wrong?
There are 3 files:
server.js
client.js
client.html
And I running server.js with node and client.html with VS Code live-server, so the address is http://127.0.0.1:5500/src/client.html
server.js
const WebSocket = require("ws");
const PORT = 9999;
let wss = new WebSocket.Server({ port: PORT });
wss.on("connection", (client) => {
client.send(`[server] ${new Date()}: hello new client`);
});
wss.on("message", (message) => {
console.log(`message from client: ${message.data}`);
});
client.js
const client = new WebSocket(`ws://localhost:${9999}`);
client.onopen = () => {
console.log("[client] connecting...");
};
client.onmessage = (message) => {
console.log(`${message.data}`);
};
function PING() {
console.log("[client] sending PING...");
client.send("PING");
}
client.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<button onclick="PING()">PING</button>
<script src="./client.js" defer></script>
</body>
</html>
Tried different things from other answers. It didn't help.

where you have
wss.on("connection", (client) => {
client.send(`[server] ${new Date()}: hello new client`);
});
This is not returning a client object, it's returning the new ws connection, so try this..
wss.on("connection", (ws) => {
ws.send(`[server] ${new Date()}: hello new client`);
ws.on('message',(msg) => console.log({ msg }));
});

wss.on("message", (message) => {
console.log(`message from client: ${message.data}`);
});
goes within
wss.on("connection", (client) => {
client.send(`[server] ${new Date()}: hello new client`);
client.on("message", (message) => {
console.log(`message from client: ${message.data}`);
});
});

Related

Express.js websocket server crashes when I refresh my browser

I have a simple Express.js app which starts a websocket server and then the front-end connects to this server. When I start both the back-end Express.js server and the front-end server, everything works fine and I can see the incoming messages from the back-end being logged in the front-end each second.
However, when I refresh my browser, the Express.js server crashes and logs this:
Error: WebSocket is not open: readyState 3 (CLOSED)
The Express.js code looks like this:
import * as WebSocket from 'ws';
const wss = new WebSocket.Server({ server });
const connect = function () {
const wss = new WebSocket.Server({ server });
wss.on('connection', (ws) => {
ws.send(createMessage());
setInterval(() => {
ws.send(generateMsg());
}, 1000);
ws.on('error', (err) => {
console.warn(`Client disconnected - reason: ${err}`);
setTimeout(() => {
connect();
}, 1000)
})
});
}
connect();
And in my front-end, I have this:
private subject = webSocket("ws://localhost:8999");
connect() {
this.subject.subscribe(
(msg) => {
console.log(msg);
},
err => {
setTimeout(() => {
this.connect();
}, 1000)
},
() => console.log('complete')
);
}
connect();
Any ideas why the reconnection between the front-end and the back-end doesn't work?

WebSocket connection timing out

I'm writing a WebSocket connection between a JavaScript client and node.JS server.
My client code:
<!DOCTYPE html>
<html>
<head>
<title>Socket Test</title>
</head>
<body>
</body>
<script>
const ws = new WebSocket('wss://mydomain.in:26031/');
ws.onopen = function () {
console.log('WebSocket Client Connected');
ws.send('Hi this is web client.');
};
ws.onmessage = function (e) {
console.log("Received: '" + e.data + "'");
};
</script>
Server code:
const net = require('net');
const server = net.createServer((socket) => {
socket.on('data', (data) => {
console.log(data.toString());
});
socket.write('SERVER: Hello! This is server speaking.\n');
socket.end('SERVER: Closing connection now.\n');
}).on('error', (err) => {
console.error(err);
});
server.listen(26031, () => {
console.log('opened server on', server.address().port);
});
The error i'm Getting:
WebSocket connection to 'wss://mydomain.in:26031/' failed: Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT
I tried other answers in stack overflow, but everything seems perfect from my side. The server port is open for accepting request. What else might be wrong?
Use "wss://" only when you have SSL install
Or else try with ws://
You can also try using Socket.IO for socket connection.

How to send broadcast to all connected client in node js

I'm a newbie working with an application with MEAN stack. It is an IoT based application and using nodejs as a backend.
I have a scenario in which I have to send a broadcast to each connected clients which can only open the Socket and can wait for any incoming data. unless like a web-browser they can not perform any event and till now I have already gone through the Socket.IO and Express.IO but couldn't find anything which can be helpful to achieve what I want send raw data to open socket connections'
Is there any other Node module to achieve this. ?
Here is the code using WebSocketServer,
const express = require('express');
const http = require('http');
const url = require('url');
const WebSocket = require('ws');
const app = express();
app.use(function (req, res) {
res.send({ msg: "hello" });
});
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
wss.on('connection', function connection(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
}
}
wss.broadcast = function broadcast(msg) {
console.log(msg);
wss.clients.forEach(function each(client) {
client.send(msg);
});
};
server.listen(8080, function listening() {
console.log('Listening on %d', server.address().port);
});
Now, my query is when this code will be executed,
wss.on('connection', function connection(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
}
}
var WebSocketServer = require("ws").Server;
var wss = new WebSocketServer({port:8100});
wss.on('connection', function connection(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
}
}
wss.broadcast = function broadcast(msg) {
console.log(msg);
wss.clients.forEach(function each(client) {
client.send(msg);
});
};
Try the following code to broadcast message from server to every client.
wss.clients.forEach(function(client) {
client.send(data.toString());
});
Demo server code,
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: 2055 },()=>{
console.log('server started')
})
wss.on('connection', (ws) => {
ws.on('message', (data) => {
console.log('data received \n '+ data)
wss.clients.forEach(function(client) {
client.send(data.toString());
});
})
})
wss.on('listening',()=>{
console.log('listening on 2055')
})

Does React Native require more websocket configuration?

I´ve set up a websocket connection by following this "guide":
https://facebook.github.io/react-native/docs/network.html
My code so far, first block in React Native:
ws = new WebSocket("ws://localhost:8087/");
ws.onopen = () => {
ws.send('something');
};
ws.onmessage = (e) => {
this.setState({ message: e.data });
};
Second block, my node server:
const WebSocketServer = require('ws').Server;
const wss = new WebSocketServer({ port: 8087 });
const messages = [];
wss.on('connection', (ws) => {
messages.forEach((message) => {
ws.send(message);
});
ws.on('message', (message) => {
messages.push(message);
console.log('Message Received: %s', message);
wss.clients.forEach((conn) => {
conn.send(message);
});
});
});
It works fine but when I deploy, do I need to set up a another server with websocket connection other than the one React Native provides?

Simple Way to Implement Server Sent Events in Node.js?

I've looked around and it seems as if all the ways to implement SSEs in Node.js are through more complex code, but it seems like there should be an easier way to send and receive SSEs. Are there any APIs or modules that make this simpler?
Here is an express server that sends one Server-Sent Event (SSE) per second, counting down from 10 to 0:
const express = require('express')
const app = express()
app.use(express.static('public'))
app.get('/countdown', function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
})
countdown(res, 10)
})
function countdown(res, count) {
res.write("data: " + count + "\n\n")
if (count)
setTimeout(() => countdown(res, count-1), 1000)
else
res.end()
}
app.listen(3000, () => console.log('SSE app listening on port 3000!'))
Put the above code into a file (index.js) and run it: node index
Next, put the following HTML into a file (public/index.html):
<html>
<head>
<script>
if (!!window.EventSource) {
var source = new EventSource('/countdown')
source.addEventListener('message', function(e) {
document.getElementById('data').innerHTML = e.data
}, false)
source.addEventListener('open', function(e) {
document.getElementById('state').innerHTML = "Connected"
}, false)
source.addEventListener('error', function(e) {
const id_state = document.getElementById('state')
if (e.eventPhase == EventSource.CLOSED)
source.close()
if (e.target.readyState == EventSource.CLOSED) {
id_state.innerHTML = "Disconnected"
}
else if (e.target.readyState == EventSource.CONNECTING) {
id_state.innerHTML = "Connecting..."
}
}, false)
} else {
console.log("Your browser doesn't support SSE")
}
</script>
</head>
<body>
<h1>SSE: <span id="state"></span></h1>
<h3>Data: <span id="data"></span></h3>
</body>
</html>
In your browser, open localhost:3000 and watch the SSE countdown.
I'm adding a simple implementation of SSE here. It's just one Node.js file.
You can have a look at the result here: https://glossy-ox.glitch.me/
const http = require('http');
const port = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
// Server-sent events endpoint
if (req.url === '/events') {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
...(req.httpVersionMajor === 1 && { 'Connection': 'keep-alive' })
});
const refreshRate = 1000; // in milliseconds
return setInterval(() => {
const id = Date.now();
const data = `Hello World ${id}`;
const message =
`retry: ${refreshRate}\nid:${id}\ndata: ${data}\n\n`;
res.write(message);
}, refreshRate);
}
// Client side
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(`
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>SSE</title>
</head>
<body>
<pre id="log"></pre>
</body>
<script>
var eventSource = new EventSource('/events');
eventSource.onmessage = function(event) {
document.getElementById('log').innerHTML += event.data + '<br>';
};
</script>
</html>
`);
});
server.listen(port);
server.on('error', (err) => {
console.log(err);
process.exit(1);
});
server.on('listening', () => {
console.log(`Listening on port ${port}`);
});
If you're using express this is the easiest way https://www.npmjs.com/package/express-sse
on BE:
const SSE = require('express-sse');
const sse = new SSE();
...
app.get('/sse', sse.init);
...
sse.send('message', 'event-name');
on FE:
const EventSource = require('eventsource');
const es = new EventSource('http://localhost:3000/sse');
es.addEventListener('event-name', function (message) {
console.log('message:', message)
});
I found SSE implementation in node.js.
Github link: https://github.com/einaros/sse.js
NPM module:https://www.npmjs.com/package/sse
Will above link helps you ?
**client.js**
var eventSource = new EventSource("/route/events");
eventSource.addEventListner("ping", function(e){log(e.data)});
//if no events specified
eventSource.addEventListner("message", function(e){log(e.data)});
**server.js**
http.createServer((req, res)=>{
if(req.url.indexOf("/route/events")>=){
res.setHeader('Connection', 'keep-alive');
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Content-Type", "text/event-stream");
let event = "event: ping";
let id = `id: ${Date.now()}`;
let data = {
message:`hello #${new Date().toString()}`
}
data = "data: "+JSON.stringify(data);
res.end(`${event}\n${id}\n${data}\n\n`);
}
}).listen(PORT)
After looking at the other answers I finally got this working, but what I ended up having to do was a little different.
[package.json] Use express-sse:
The exact version of express-sse is very important. The latest tries to use res.flush(), but fails and crashes the http server.
"express-sse": "0.5.1",
[Terminal] Install express-sse:
npm install
[app.js] Use the router:
app.use(app.baseUri, require('./lib/server-sent-events').router);
[server-sent-events.js] Create sse library:
The call to pause() is the equivalent of flush(), which was removed from express. It ensures you'll keep getting messages as they are sent.
var express = require('express');
const SSE = require('express-sse');
const sse = new SSE();
var router = express.Router();
router.get('/sse', sse.init)
module.exports = {
send,
router
};
async function send(message) {
sse.send(message.toProperCase(), 'message');
await pause();
}
function pause() {
return new Promise((resolve, reject) => {
setImmediate(resolve)
})
}
[your-router.js] Use the sse library and call send:
var express = require('express');
var serverSentEvents = require('../lib/server-sent-events');
var router = express.Router();
router.get('/somepath', yourhandler);
module.exports = router;
async function yourhandler (req, res, next) {
await serverSentEvents.send('hello sse!'); // <<<<<
}
[your-client-side.js] Receive the sse updates:
I recommend you keep the event.data.replace(/"/g,'') because express-sse tacks on enclosing quotes and we don't want those.
const eventSource = new EventSource('http://yourserver/sse');
eventSource.onmessage = function(event) {
document.getElementById("result").innerHTML = event.data.replace(/"/g,'') + '...';
};
You should be able to do such a thing using Socket.io. First, you will need to install it with npm install socket.io. From there, in your code you will want to have var io = require(socket.io);
You can see more in-depth examples given by Socket.IO
You could use something like this on the server:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('../..')(server);
var port = process.env.PORT || 3000;
server.listen(port, function () {
console.log('Server listening at port ' + port);
});
app.use(express.static(__dirname + '/public'));
io.on('connection', function (socket) {
socket.emit('EVENT_NAME', {data});
});
And something like this on the client:
<script src="socket_src_file_path_here"></script>
<script>
var socket = io('http://localhost');
socket.on('EVENT_NAME', function (data) {
console.log(data);
//Do whatever you want with the data on the client
});
</script>

Categories