unable to create simple websocket - NodeJS - javascript

I am trying to follow this tutorial: https://www.simonewebdesign.it/101-web-socket-protocol-handshake/ for developing simple websocket protocol.
I am visiting localhost:1337/index.html but I get:
This localhost page can’t be found
No web page was found for the web address: http://localhost:1337/index.html
Search Google for localhost 1337 index
HTTP ERROR 404
if I visit this url: file:///C:/Users/.../websocket-demo/index.html
I atleast see the index.html page being rendered. But in console I get this error:
WebSocket connection to 'ws://localhost:1337/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
I am not sure what's wrong?
I have 3 files: index.html, server.js and client.js
server.js
#!/usr/bin/env node
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
console.log('Received request from ' + request.url);
response.writeHead(404);
response.end();
});
server.listen(1337, function() {
console.log('Server is listening on port 1337.');
});
wsServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: false // because security matters
});
function isAllowedOrigin(origin) {
console.log('Connection requested from origin ' + origin);
valid_origins = [
'http://localhost:8080',
'127.0.0.1',
'null'
];
if (valid_origins.indexOf(origin) != -1) {
console.log('Connection accepted from origin ' + origin);
return true;
}
console.log('Origin ' + origin + ' is not allowed.')
return false;
}
wsServer.on('connection', function(webSocketConnection) {
console.log('Connection started.');
});
wsServer.on('request', function(request) {
var connection = isAllowedOrigin(request.origin) ?
request.accept('echo-protocol', request.origin)
: request.reject();
connection.on('message', function(message) {
var response = '';
console.log('Received Message: ' + message.utf8Data);
if (message.type === 'utf8') {
switch (message.utf8Data) {
case 'hi':
response = 'Hey there';
break;
case 'hello':
response = 'Heya!';
break;
case 'xyzzy':
response = 'Nothing happens.';
break;
case 'desu':
response = 'Keep typing, man. Keep typing.';
break;
default:
response = "Hello. Uh... what am I supposed to do with '" +
message.utf8Data + "'?";
}
connection.sendUTF(response);
}
});
connection.on('close', function(reasonCode, description) {
console.log(connection.remoteAddress + ' has been disconnected.');
});
});
client.js
(function () {
var ws = new WebSocket('ws://localhost:1337', 'echo-protocol');
ws.onopen = function (event) {
console.log('Connection opened.');
}
ws.onmessage = function (event) {
console.log('Response from server: ' + event.data);
}
ws.onclose = function (event) {
console.log('Connection closed.');
}
ws.onerror = function (event) {
console.log('An error occurred. Sorry for that.');
}
WebSocket.prototype.sendMessage = function (message) {
this.send(message);
console.log('Message sent: ' + message);
}
document.getElementById('send').addEventListener('click', function (event) {
event.preventDefault();
var message = document.getElementById('message').value;
ws.sendMessage(message);
});
})();
index.html - consist of forms
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>WebSocket Client Demo</title>
</head>
<body>
<h1>WebSocket Client</h1>
<form>
<label for="message">Send a message</label>
<input id="message" name="message" type="text">
<button id="send" name="send">Send</button>
</form>
<script src="client.js"></script>
</body>
</html>

Your web server doesn't serve your index.html file.
You can see this post to get an idea how to serve static files, or you can just boot up another HTTP server to serve your index file, like with python, the way they suggested in the README file of the tutorial that you are following: https://github.com/simonewebdesign/websocket-demo

Related

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.

Websocket - browser websocket is not receiving messages from server

I built a websocket server and client with Node and both is working fine. But, I built a client on a single html page and there, websocket is listening messages just when I call sendUTF from browser. The messages sent by node client can´t be read by browser client. Is this a security issue/feature or am I stupid?
Server code:
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer( (req, res) => {
console.log((new Date()) + ' Received request for ' + request.url);
res.writeHead(404);
res.end();
});
server.listen(8080, () => {
console.log((new Date()) + ' Server is listening on port 8080');
});
wsServer = new WebSocketServer({
httpServer: server,
// You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: false
});
function originIsAllowed(origin) {
// put logic here to detect whether the specified origin is allowed.
return true;
}
wsServer.on('request', (request) => {
/* if (!originIsAllowed(request.origin)) {
// Make sure we only accept requests from an allowed origin
request.reject();
console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
return;
}*/
var connection = {};
try {
connection = request.accept('echo-protocol', request.origin);
console.log((new Date()) + ' Connection accepted.');
connection.on('message', function(message) {
if (message.type === 'utf8') {
console.log('Received and send Message: ' + message.utf8Data);
connection.sendUTF(message.utf8Data);
}
else if (message.type === 'binary') {
console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
connection.sendBytes(message.binaryData);
}
else {
console.log('Received unknown format message: ' + message);
connection.send(message);
}
});
connection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
});
}
catch(e) {
console.error("Client fail trying to connect to websocket: " + e);
}
});
Node client code:
var express = require('express');
var app = express();
server = require('http').createServer(app);
var WebSocketClient = require('websocket').client;
var kinect = new Kinect2();
app.use(express.static(__dirname + 'js/View'));
//app.use(express.static(__dirname + 'js/Script'));
//instance of WebSocket object
var wsClient = new WebSocketClient();
//Websocket connection events
wsClient.on('connectFailed', function(error) {
console.log('Connect Error: ' + error.toString());
process.exit(0);
});
wsClient.on('connect',(connection) => {
connection.on('error', (error) => {
console.error("Connection Error: " + error.toString());
process.exit(0);
});
connection.on('close',() => {
console.log("Websocket connection is closed!");
});
// connection.on('message',(message) => {
// if (message.type === 'utf8') {
// console.log("Received: '" + message.utf8Data + "'");
// }
// });
console.log('Websocket connection OK!');
setInterval(() => {
console.log("sending message...");
connection.send("This is a test!");
},1000);
//startKinect(connection);
});
wsClient.connect('ws://127.0.0.1:8080','echo-protocol');
Finally my browser client
<!DOCTYPE html>
<html>
<head>
<title>
Websocket test
</title>
</head>
<body>
<h1>Websocket client test</h1>
<script>
console.log("Open Websocket...");
var websocket = new WebSocket('ws://127.0.0.1:8080','echo-protocol');
websocket.onopen = function () {
console.log("websocket was open");
//websocket.send('Websocket is working(I gess)');
};
websocket.onclose = () => {
console.log("Websocket was closed!");
}
websocket.onerror = (error) =>{
console.error("Websocket error: " + JSON.stringify(error));
};
websocket.onmessage = (message) => {
// Web Socket message:
console.log("MSG: " + message.data );
};
websocket.addEventListener('message',(e) => {
websocket.onmessage(e);
})
</script>
</body>
</html>
Any help is welcome! Thanks!
Your server is working as an echo (client -> server -> client), but what you describe is a broadcast (client -> server -> clients). You should keep a reference of clients and then send to all of them.
Outside of the request event handler, add:
var connections = [];
After your accept the request, add the connection to the array:
connections.push( connection );
And then when you want to send data to everyone, loop through the connections:
for ( var i = 0; i < connections.length; i++ )
connections[ i ].sendUTF( message.utf8Data );
It seems I miss the 'broadcast' part. Fortunately, 'ws' module allows me to do this extreamly easy!
const WebSocket = require('ws');
var port = 8080;
const wss = new WebSocket.Server({ "port": port });
// Broadcast to all.
wss.broadcast = function broadcast(data) {
wss.clients.forEach(function each(client) {
if ( client.readyState == WebSocket.OPEN && data != undefined )
client.send(data);
});
};
wss.on('connection', function connection(ws) {
console.log("CONNECTION OK...");
ws.on('message', function incoming(data) {
// Broadcast to everyone else.
wss.broadcast(data);
});
});

How to authenticate every request over a websocket in javascript?

Have setup a javascript server and configured the websocket to it. On the client side using react and npm. So, I want to authenticate every request to web socket using rest API. The authentication will be the first step and then all the information transfer will be happening using the same web socket after authentication is done. Is it possible to pass headers for authentication to websocket ? Can anybody please tell how to proceed ?
Below is the code for the server and client that I was experimenting with.
Server code -
#!/usr/bin/env node
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
console.log((new Date()) + ' Received request for ' + request.url);
response.writeHead(404);
response.end();
});
server.listen(5005, function() {
console.log((new Date()) + ' Server is listening on port 5005');
});
wsServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: false
});
function originIsAllowed(origin) {
return true;
}
wsServer.on('request', function(request) {
if (!originIsAllowed(request.origin)) {
request.reject();
console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
return;
}
console.log(" ################ Authorization ##################");
var auth = request.headers['authorization'];
if(!auth) {
response.statusCode = 401;
response.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
console.log(" Authorization failed !!! ");
response.end('<html><body>Need some creds son</body></html>');
}
else if(auth) {
var tmp = auth.split(' ');
var buf = new Buffer(tmp[1], 'base64');
var plain_auth = buf.toString();
console.log("Decoded Authorization :", plain_auth);
var creds = plain_auth.split(':');
var username = creds[0];
var password = creds[1];
if((username == 'hack') && (password == 'thegibson')) {
console.log(" Login successful !!!");
}
else {
console.log("Login failed !!");
}
}
var connection = request.accept('echo-protocol', request.origin);
console.log((new Date()) + ' Connection accepted.');
connection.on('message', function(message) {
//send message
});
connection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
});
});
Client code -
import React from 'react'
var client = null;
export default React.createClass({
getInitialState: function() {
return { val : [],
username : 'hacker',
password : 'thegibson' };
},
componentWillMount: function() {
//client = new WebSocket('ws://localhost:8000/','echo-protocol');
client = new WebSocket('ws://'+this.state.username+':'+this.state.password+'#localhost:5005/','echo-protocol');
client.onerror = function() {
console.log('Connection Error');
};
client.onopen = function() {
function sendData(){
var details=[{"name" : "Ravi", "age" : 15, "occupation": "Student" }];
if (client.readyState === client.OPEN) {
client.send(details.toString());
console.log(details);
setTimeout(sendData,2000);
}
}
sendData();
};
client.onmessage = function(e) {
this.setState({
val: e.data
});
}.bind(this);
},
componentWillUnmount: function(){
client.close();
},
render: function() {
return (React.createElement("div",null,
React.createElement("ul",null,
React.createElement("li",null,this.state.val.name," ( ", this.state.val.age," ) - "," Occupation :", this.state.val.occupation)
)
))
}
});
Maybe you can use jwt or jwe if you want to encrypt the data you send. There are many libraries you can use and full documentation here: https://jwt.io/
So you cand send via post or a header all information and check it in every HTTP or websocket call

How to get the variable req with ExpressJS and BinaryJS

I'm doing an upload/streaming server with nodeJS, ExpressJS and BinaryJS for the websocket. Separately, everything works good but the user has to be authentified to upload a video and that's my problem so I need the variable 'req'.
When I use BinaryJS on my express server, I don't have access to the variable 'req' at it is specified in the doc (https://github.com/binaryjs/binaryjs/blob/master/doc/api.md, https://github.com/binaryjs/binaryjs/blob/master/doc/start.md) I use an endpoint but that doesn't work.
When I split the server the ExpressJS server and the BinaryJS server:
Server:
var express = require('express');
var app = express();
var BinaryServer = require('binaryjs').BinaryServer;
app.listen(8080);
var bs = new BinaryServer({port: 9000});
function request(client, meta) {
console.log("request");
}
function upload(stream, meta) {
console.log("upload");
stream.write({ end: true });
}
bs.on('connection', function (client) {
client.on('stream', function (stream, meta) {
switch(meta.event) {
case 'stream':
request(client, meta);
break;
case 'upload':
upload(stream, meta);
}
});
});
console.log('The magic happens on port ' + port);
Client:
<html>
<body>
<div>
<div>
<input type="file" name="video" id="video" />
<p id="progress"></p>
<button type="submit" id="submit">Upload</button>
</div>
</div>
<script src="http://cdn.binaryjs.com/0/binary.js"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-migrate-1.2.1.min.js" />
<script>
var hostname = window.location.hostname;
var client = new BinaryClient('ws://' + hostname + ':9000');
$('#submit').click(function(){
var file, tx;
file = $('#video')[0].files[0];
tx = 0;
upload(file, function (err, data) {
if (data.end) {
console.log("Upload complete: " + file.name);
} else if (data.rx) {
console.log(Math.round(tx += data.rx * 100) + '% complete');
} else {
console.log(data.err);
}
});
});
function upload(file, cb) {
var stream = client.send(file, {name : file.name, size : file.size, type : file.type, event : 'upload'});
stream.on('data', function (data) {
cb(null, data);
});
stream.on('error', cb);
}
</script>
</body>
</html>
This code works perfectly but i don't have access to the variable 'req', so I did like it is specified in the documentation but I am probably wrong:
Server:
var express = require('express');
var app = express();
var BinaryServer = require('binaryjs').BinaryServer;
app.listen(8080);
var bs = new BinaryServer({port: 9000});
function request(client, meta) {
console.log("request");
}
function upload(stream, meta) {
console.log("upload");
stream.write({ end: true });
}
app.get('/binary-endpoint', function(req, res) {
console.log("get");
});
app.post('/binary-endpoint', function(req, res) {
console.log("post");
});
bs.on('connection', function (client) {
client.on('stream', function (stream, meta) {
switch(meta.event) {
case 'stream':
request(client, meta);
break;
case 'upload':
upload(stream, meta);
}
});
});
console.log('The magic happens on port ' + port);
Just this line changes in the client:
var client = new BinaryClient('ws://' + hostname + ':8080/binary-endpoint');
But nothing happen in the server, no log is diplayed and I get this message in the client console:
GET http://127.0.0.1/upload.html [HTTP/1.1 304 Not Modified 1ms]
GET http://cdn.binaryjs.com/0/binary.js [HTTP/1.1 304 Not Modified 102ms]
GET http://code.jquery.com/jquery-1.11.0.min.js [HTTP/1.1 304 Not Modified 26ms]
GET http://code.jquery.com/jquery-migrate-1.2.1.min.js [HTTP/1.1 304 Not Modified 48ms]
GET http://localhost:8080/binary-endpoint [168ms]
Firefox can't establish a connection to the server at ws://localhost:8080/binary-endpoint. binary.js:1341
GET http://null/ [2252ms]
Error: Client is not yet connected or has closed binary.js:1539
Firefox can't establish a connection to the server at ws://null/.
Thanks for your help

How to emit event with Socket.io and Node.js?

I find it hard to emit an event because I don't know much about creating an event/emitting an event with socket IO.
Here is my problem on CASE "/publish":
var app = http.createServer(function (req, res) {
if (req.method == "OPTIONS") {
res.header('Access-Control-Allow-Origin', '*:*');
res.send(200);
} else {
var u = url.parse(req.url,true),
body = '';
req.on('data',function(chunk) {
body += chunk;
});
req.on('end',function() {
if(body) {
var data =JSON.parse(body);
if(data._app_secret && data._app_secret == 'nonexistent') {
switch(u.pathname) {
case '/generateusersecret' :
findTokenByUser(req.headers.host+'_'+data.user_id,function(reply) {
if(reply) {
jsonResponse(res,{userSecret : reply});
} else {
generateToken(req.headers.host + '_' + data.user_id,data.user_id,res);
}
});
break;
case '/getusersecret' :
findTokenByUser(req.headers.host + '_' + data.user_id,function(reply) {
jsonResponse(res,{userSecret : reply});
console.log(reply);
});
break;
case '/publish':
if(data.type == 'notification'){
var newData = {
item_id : data.item_id,
message : data.message,
recipient : data.channel,
itemLink : data.itemLink,
timestamp : data.timestamp,
read : 0
}
notification = JSON.stringify(newData);
// I need to emit my event here
Socket.emit(THE EVENT HERE,notification DATA)
}
break;
default:
jsonResponse(res,{error : "Unknown Command: " + u.pathname});
break
}
} else {
res.writeHead(403, {'Content-Type': 'text/plain'});
res.end('Not authorized');
}
}
});
}
});
app.listen(config.port || 4000, null);
Then I need to listen on:
io.sockets.on('connection'function(socket){
socket.on('THE EVENT HERE',function(NOTIFICATION DATA){
//I NEED TO EMIT ANOTHER EVENT HERE
})
})
Is there a possible way for this? I have to do this because I am using PHP's cURL and I can't emit on client side so I need to emit it on server side.
It seems you need to emit an event from the server-side, this is possible and the main feature from socket.io.
To broadcast to all connected sockets use this code in the /publish endpoint:
io.sockets.emit('event', data);
Socket.io can also broadcast messages to group of sockets, this feature is called rooms.
If you want to send a message to only one socket, you can mark the sockets with an extra property when they connect and then search those sockets in the list of connected sockets.
Complete example:
Server side (server.js):
var http = require('http');
var fs = require('fs');
var server = http.createServer(handler);
var io = require('socket.io').listen(server);
function handler (req, res) {
if (req.url === '/') {
return fs.createReadStream(__dirname + '/index.html').pipe(res);
}
if (req.url === '/publish' && req.method === 'POST') {
//this is what you are looking for:
io.sockets.emit('super event', { message: 'hello' });
//---------------------------------
res.writeHead(200, {
'Location': '/'
});
return res.end('');
}
}
io.sockets.on('connection', function (socket) {
socket.on('publish', function (data) {
//if you need to emit to everyone BUT the socket who emit this use:
//socket.broadcast.emit('super event', data);
//emit to everyone
io.sockets.emit('super event', data);
})
});
server.listen(1080, function () {
console.log('listening on http://localhost:1080');
});
Client side (index.html):
<html>
<head>
</head>
<body>
hello world.
<form action="/publish" method="post">
<input type="submit" value="send a notification"></input>
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('/');
socket.on('super event', function (data) {
console.log(data);
alert('got a message!');
});
</script>
</body>
</html>
Usage
Put these two files in one directories.
npm i socket.io
node server.js
open two tabs in the browser pointing to http://localhost:1080
click the send notification button in one of the tabs

Categories