I have a working node.js Server that uses a socket.io websocket connection and ssh2 connection to open a shell and return it to a react client in the browser that uses xterm-for-react. I'm now trying to also tunnel a port over the same ssh connection but am having some difficulty. The code is below and the commented out part is where I've been trying to do the port forwarding - equivalent to
ssh -L 2233:192.168.2.1:80 test#192.168.0.65
const socketIO = require("socket.io");
const sshClient = require("ssh2").Client;
const utf8 = require("utf8");
const fs = require("fs");
class SocketServiceFwd {
constructor() {
this.socket = null;
this.pty = null;
this.devicesList = [
{
name: "Device 1",
host: "192.168.0.65",
port: "22",
username: "test",
password: "test12345",
},
];
attachServer(server) {
if (!server) {
throw new Error("Server not found...");
}
const io = socketIO(server, {cors: {origin: "*",},});
console.log("Created socket server. Waiting for client connection.");
// "connection" event happens when any client connects to this io instance.
io.on("connection", (socket) => {
console.log("Client connect to socket.", socket.id);
this.socket = socket;
const ssh = new sshClient();
this.socket.on("devices", (cb) => {
console.log("Get devices list from " + socket.id);
return cb(null,this.devicesList.map((d) => ({ name: d.name }))
);
});
this.socket.on("connectToDevice", (deviceName) => {
console.log(socket.id + " connecting to device " + deviceName);
const selectedDevice = this.devicesList.find(
(d) => d.name === deviceName
);
if (selectedDevice) {
ssh.on("ready", function () {
console.log(socket.id + " successfully connected to " + deviceName);
socket.emit("output", "\r\n*** SSH CONNECTION ESTABLISHED ***\r\n");
// ssh.forwardOut("127.0.0.1", 2233, "192.168.2.1", 80,
// (err, stream) => {
// console.log(
// "ssh forwardOut '127.0.0.1:2233' '192.168.2.1:80'"
// );
// if (err)
// return socket.emit(
// "output",
// "\r\n*** SSH FORWARDOUT ERROR: " + err.message + " ***\r\n"
// );
// }
// );
ssh.shell(function (err, stream) {
if (err)
return socket.emit(
"output",
"\r\n*** SSH SHELL ERROR: " + err.message + " ***\r\n"
);
socket.on("input", function (data) {
stream.write(data);
});
stream.on("data", function (d) {
socket.emit("output", utf8.decode(d.toString("binary")));
});
stream.on("close", function () {
console.log(socket.id + " terminal stream close");
ssh.end();
});
});
});
ssh.on("close", function () {
console.log(socket.id + " ssh connection closed to " + deviceName);
socket.emit("output", "\r\n*** SSH CONNECTION CLOSED ***\r\n");
socket.removeListener("input", () => {});
});
ssh.on("error", function (err) {
console.log(err);
socket.emit("output","\r\n*** SSH CONNECTION ERROR: " + err.message + " ***\r\n");
});
ssh.connect(selectedDevice);
}
});
this.socket.on("disconnectFromDevice", () => {
console.log(socket.id + " disconnecting from device");
ssh.destroy();
});
});
}
}
module.exports = SocketServiceFwd;
***** EDITED *****
It would be great if someone could please provide some advice :-) I have been pushing ahead but still need some assistance...
I have had a little more success using the npm "tunnel-ssh" module. The tunnel does open long enough for me to view the website but shortly after that, the tunnel stops working. Is there something else I'm supposed to be doing after opening the tunnel?
The code below goes where the commented out section above is. I have tried to follow the examples I've seen online - can anyone please advise me what I'm doing wrong?
I'm running DEBUG=* in my npm start and see the following :
tunnel-ssh sshConnection:ready +3s
tunnel-ssh sshConnection:ready +1ms
tunnel-ssh sshStream:create +19ms
tunnel-ssh sshStream:create +0ms
TCP :: ERROR: read ECONNRESET
TCP :: ERROR: read ECONNRESET
So It's clear that the tunnel starts up but then an error occurs. Often the connection recovers and I can continue browsing the website through the tunnel, but eventually an unrecoverable error occurs. So the tunnel is unstable. If i run the tunnel using openssh it is stable. Therefore my question really now boils down to a request for assistance in determining reasons for the instability. Am I not handling something in my code or my configuration correctly? Please Help! Note also, that despite this my shell session continues to work without any problem.
const tunnel = require("tunnel-ssh");
const tnl = tunnel({host: '192.168.0.65', username: 'test', password: 'test12345',
dstHost: '192.168.2.1', dstPort: 80, localHost: '127.0.0.1',
localPort: 2233}, (er, stream) => {
if(er) {
console.log("something went wrong " + er.message);
stream.close();
}
stream.on("data", (data) => {
console.log("TCP :: DATA: " + data);
});
stream.on("error", (error) => {
console.log("TCP :: ERROR: " + error.message);
});
});
Related
I use mosca (for node js) to create a MQTT server and MQTT (still node js) package to create publishers and subscribers. Everything work good except one thing: publisher reload automatically
I guess it may be due to incorrect mqtt.connect options. I read npm mqtt manual but still don't understand my mistake (or mistakes)
P.s. Sorry for my grammatical, I'm not an English speaker
UPD: i'm beginner :)
MQTT Server:
const mosca = require("mosca");
const MqttServer = new mosca.Server({
port: 1884
});
MqttServer.on("clientConnected", function(client) {
console.log('\x1b[0m', 'Клиент ' + '\x1b[32m' + client.id + '\x1b[32m' + ' подключен!' + '\x1b[0m');
});
MqttServer.on("clientDisconnected", function(client) {
console.log('\x1b[0m', 'Клиент ' + '\x1b[32m' + client.id + '\x1b[31m' + ' Отключен' + '\x1b[0m');
})
MqttServer.on("ready", function() {
console.log("Server MQTT Room1 running");
});
MqttServer.on("error", function(error) {
console.log("error!");
client.end();
})
Subscribe script:
const mqtt = require("mqtt");
const options = {
clientId: 'mqtt_room1_SUB',
clean: true
};
const client = mqtt.connect("mqtt://127.0.0.1:1884", options);
client.on("connect", function() {
console.log("Connected");
// connected = client.connected
client.subscribe("room1/temp", { qos: 0 });
});
client.on("message", function(top, message) {
console.log("Current temperature:", message.toString());
});
client.on("disconnect", function () {
console.log('Server disabled.')
})
Publish script:
const mqtt = require("mqtt");
const options = {
clientId: 'mqtt_room1_PUB',
clean: true
};
const client = mqtt.connect("mqtt://127.0.0.1:1884", options);
client.on("connect", function() {
console.log("Connected");
setInterval(() => {
var value = Math.floor(Math.random() * 20);
client.publish("room1/temp", value.toString());
}, 2000);
});
client.on("disconnect", function () {
console.log('Server disabled.');
});
I have two backends. Backend A and Backend B.
Backend B sends and receives info using a socket server running at port 4243.
Then, with Backend A, I need to catch that info and save it. But I have to also have a socket server on Backend A running at port 4243.
The problem is that, when I run Backend A after running Backend B I receive the error "EADDRINUSE", because I'm using the same host:port on both apps.
If, for Backend A I use Python, the problem dissapear because I have a configuration for sockets that's called SO_REUSEADDR.
Here we have some examples:
https://www.programcreek.com/python/example/410/socket.SO_REUSEADDR
https://subscription.packtpub.com/book/networking-and-servers/9781849513463/1/ch01lvl1sec18/reusing-socket-addresses
But, I want to use JavaScript for coding my Backend A, so I was using the net package for coding the sockets, and I can't get it to work, because of the "EADDRINUSE" error.
The NodeJS documentation says that "All sockets in Node set SO_REUSEADDR already", but it doesn't seem to work for me...
This is my code so far:
// Step 0: Create the netServer and the netClient
console.log(`[DEBUG] Server will listen to: ${HOST}:${PORT}`);
console.log(`[DEBUG] Server will register with: ${AGENT_ID}`);
const netServer = net.createServer((c) => {
console.log('[netServer] Client connected');
c.on('message', (msg) => {
console.log('[netServer] Received `message`, MSG:', msg.toString());
});
c.on('*', (event, msg) => {
console.log('[netServer] Received `*`, EVENT:', event);
console.log('[netServer] Received `*`, MSG:', msg);
});
}).listen({
host: HOST, // 'localhost',
port: PORT, // 4243,
family: 4, // ipv4, same as socket.AF_INET for python
});
// Code copied from nodejs documentation page (doesn't make any difference)
netServer.on('error', function (e) {
if (e.code == 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(function () {
netServer.close();
netServer.listen(PORT, HOST);
}, 1000);
}
});
const netClient = net.createConnection(PORT, HOST, () => {
console.log('[netClient] Connected');
});
// Step 1: Register to instance B of DTN with agent ID 'bundlesink'
netClient.write(serializeMessage({
messageType: AAPMessageTypes.REGISTER,
eid: AGENT_ID,
}));
With this code, I get the following output in the terminal:
But, with the Python code, the socket connects successfully:
I don't know what to do :(
I hope I get some help here.
Edit 1
By the way, the lsof command, throws me this output for the JavaScript backend:
And this other output for the Python backend:
Edit 2
It really seems to be a problem with JavaScript. I also found this snippet:
var net = require('net');
function startServer(port, host, callback) {
var server = net.createServer();
server.listen(port, host, function() {
callback(undefined, server);
});
server.on('error', function(error) {
console.error('Ah damn!', error);
callback(error);
});
}
startServer(4000, '0.0.0.0', function(error, wildcardServer) {
if (error) return;
startServer(4000, '127.0.0.1', function(error, localhostServer) {
if (error) return;
console.log('Started both servers!');
});
});
From this post:
https://medium.com/#eplawless/node-js-is-a-liar-sometimes-8a28196d56b6
As the author says:
Well, that prints “Started both servers!” which is exactly what we don’t want.
But for me, instead of printing that, I get an error:
Ah damn! Error: listen EADDRINUSE: address already in use 127.0.0.1:4000
at Server.setupListenHandle [as _listen2] (node:net:1319:16)
at listenInCluster (node:net:1367:12)
at doListen (node:net:1505:7)
at processTicksAndRejections (node:internal/process/task_queues:84:21) {
code: 'EADDRINUSE',
errno: -98,
syscall: 'listen',
address: '127.0.0.1',
port: 4000
}
I really cannot make it to run and print "Started both servers!".
Because that's what I want my code to do.
Edit 3
This is the Python server socket: https://gitlab.com/d3tn/ud3tn/-/blob/master/tools/aap/aap_receive.py
This is the important part:
addr = (args.tcp[0], int(args.tcp[1])) # args.tcp[0] = "localhost", args.tcp[1] = "4243"
with AAPTCPClient(address=addr) as aap_client:
aap_client.register(args.agentid) # args.agentid = "bundlesink"
run_aap_recv(aap_client, args.count, args.verify_pl)
It creates an AAPTCPClient, and the only thing that AAPTCPClient does, is the following:
def __init__(self, socket, address):
self.socket = socket
self.address = address
self.node_eid = None
self.agent_id = None
def register(self, agent_id=None):
"""Attempt to register the specified agent identifier.
Args:
agent_id: The agent identifier to be registered. If None,
uuid.uuid4() is called to generate one.
"""
self.agent_id = agent_id or str(uuid.uuid4())
logger.info(f"Sending REGISTER message for '{agent_id}'...")
msg_ack = self.send(
AAPMessage(AAPMessageType.REGISTER, self.agent_id)
)
assert msg_ack.msg_type == AAPMessageType.ACK
logger.info("ACK message received!")
def send(self, aap_msg):
"""Serialize and send the provided `AAPMessage` to the AAP endpoint.
Args:
aap_msg: The `AAPMessage` to be sent.
"""
self.socket.send(aap_msg.serialize())
return self.receive()
def receive(self):
"""Receive and return the next `AAPMessage`."""
buf = bytearray()
msg = None
while msg is None:
data = self.socket.recv(1)
if not data:
logger.info("Disconnected")
return None
buf += data
try:
msg = AAPMessage.parse(buf)
except InsufficientAAPDataError:
continue
return msg
I don't see any bind, and I don't understand why the python code can call "socket.recv", but in my JavaScript code I can't do "netServer.listen". I think it should be the same.
There are things to clarify.
1.) The client uses the bind syscall where the kernel selects the source port automatically.
It does so by checking sys local_portrange sysctl settings.
1.) If you want to bind the client to a static source port, be sure to select a TCP port outside the local_portrange range !
2.) You cannot subscribe to event "*", instead you've to subscribe to the event "data" to receive messages.
For best practice you should also subscribe to the "error" event in case of errors !
These links will get you started right away:
How do SO_REUSEADDR and SO_REUSEPORT differ?
https://idea.popcount.org/2014-04-03-bind-before-connect/
So, for all beginners, who want to dig deeper into networking using node.js…
A working server example:
// Step 0: Create the netServer and the netClient
//
var HOST = 'localhost';
var PORT = 4243;
var AGENT_ID = 'SO_REUSEADDR DEMO';
var net = require('net');
console.log(`[DEBUG] Server will listen to: ${HOST}:${PORT}`);
console.log(`[DEBUG] Server will register with: ${AGENT_ID}`);
const netServer = net.createServer((c) => {
console.log('[netServer] Client connected');
c.on('data', (msg) => {
console.log('[netServer] Received `message`, MSG:', msg.toString());
});
c.on('end', () => {
console.log('client disconnected');
});
c.on('error', function (e) {
console.log('Error: ' + e.code);
});
c.write('hello\r\n');
c.pipe(c);
}).listen({
host: HOST,
port: PORT,
family: 4, // ipv4, same as socket.AF_INET for python
});
// Code copied from nodejs documentation page (doesn't make any difference)
netServer.on('error', function (e) {
console.log('Error: ' + e.code);
if (e.code == 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(function () {
netServer.close();
netServer.listen(HOST, PORT);
}, 1000);
}
if ( e.code = 'ECONNRESET' ){
console.log('Connection reset by peer...');
setTimeout(function () {
netServer.close();
netServer.listen(HOST, PORT);
}, 1000);
}
});
The Client:
/* Or use this example tcp client written in node.js. (Originated with
example code from
http://www.hacksparrow.com/tcp-socket-programming-in-node-js.html.) */
var net = require('net');
var HOST = 'localhost';
var PORT = 4243;
var client = new net.Socket();
client.setTimeout(3000);
client.connect(PORT, HOST, function() {
console.log("Connected to " + client.address().address + " Source Port: " + client.address().port + " Family: " + client.address().family);
client.write('Hello, server! Love, Client.');
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.end();
});
client.on('error', function(e) {
console.log('Error: ' + e.code);
});
client.on('timeout', () => {
console.log('socket timeout');
client.end();
});
client.on('close', function() {
console.log('Connection closed');
});
Best Hannes
Steffen Ullrich was completely right.
In my JavaScript code, I was trying to create a server to listen to the port 4243.
But you don't need to have a server in order to listen to some port, you can listen with a client too! (At least that's what I understood)
You can create a client connection as following:
const netClient = net.createConnection(PORT, HOST, () => {
console.log('[netClient] Connected');
});
netClient.on('data', (data) => {
console.log('[netClient] Received data:', data.toString('utf8'));
});
And with "client.on", then you can receive messages as well, as if it were a server.
I hope this is useful to someone else.
I want to make connection for unlimited times in Nodejs. For example, i write something on some server and after writing on server, server send me response of error (as expected from server) and disconnect. But i want to again make a connection to that server and again want to send request with different parameters. I am not sure where and what logic/code to be put in my following segment of code , so that i can make unlimited requests.
var net = require('net');
var HOST = '40.14.121.178'
var PORT = 12537;
var byteToSend = [0x56, 0x34, ...]
var client = new net.Socket();
client.connect(PORT, HOST, function() {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
client.write(byteToSend);
});
client.on('data', function(data) {
console.log('DATA: ' + data);
client.destroy();
});
client.on('close', function() {
console.log('Connection closed');
});
EDITED:
actually, i want to make another connection upon disconnect like following style (which is i think wrong)
client.on('close', function() {
console.log('Connection closed');
client.connect(PORT, HOST, function() {
console.log('again CONNECTED TO: ' + HOST + ':' + PORT);
client.write(byteToSend);
});
});
above re connection raise following error.
events.js:174
throw er; // Unhandled 'error' event
^
Error: write EPIPE
at afterWriteDispatched (internal/stream_base_commons.js:78:25)
at writeGeneric (internal/stream_base_commons.js:73:3)
at Socket._writeGeneric (net.js:713:5)
at Socket._write (net.js:725:8)
at doWrite (_stream_writable.js:415:12)
at writeOrBuffer (_stream_writable.js:399:5)
at Socket.Writable.write (_stream_writable.js:299:11)
at bitflipping (C:\Users\...\Desktop\myScripts.js:130:8)
at Socket.<anonymous> (C:\Users\...\Desktop\myScripts.js:104:9)
at Object.onceWrapper (events.js:286:20)
Emitted 'error' event at:
at errorOrDestroy (internal/streams/destroy.js:107:12)
at onwriteError (_stream_writable.js:430:5)
at onwrite (_stream_writable.js:461:5)
at _destroy (internal/streams/destroy.js:49:7)
at Socket._destroy (net.js:613:3)
at Socket.destroy (internal/streams/destroy.js:37:8)
at afterWriteDispatched (internal/stream_base_commons.js:78:17)
at writeGeneric (internal/stream_base_commons.js:73:3)
at Socket._writeGeneric (net.js:713:5)
at Socket._write (net.js:725:8)
I don't think you can re-use the existing client connection to connect again. Therefore, you'll want to wrap it all in a nice closure/function that you can call again to create a new socket and connect.
Try something like this:
var net = require('net');
var HOST = '40.14.121.178'
var PORT = 12537;
var byteToSend = [0x56, 0x34, ...]
function connect() {
var client = new net.Socket();
client.connect(PORT, HOST, function() {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
client.write(byteToSend);
});
client.on('data', function(data) {
console.log('DATA: ' + data);
client.destroy();
});
client.on('close', function() {
console.log('Connection closed');
connect();
});
}
connect();
If I understood correctly, you want to keep your server enabled for requests for a sort amount of time without waiting for 3-way handshake etc. To do that you should use the keep-alive attribute like this.
const net = require('net');
const HOST = '40.14.121.178'
const PORT = 12537;
const byteToSend = [0x56, 0x34, ...];
const server = net.createServer(client => {
client.setKeepAlive(true, 60000); // milliseconds.
client.on('data', data => {
console.log(`DATA: ${data}`);
client.destroy();
});
client.on('end', data => {
console.log('Connection closed');
});
client.on('connect', data => {
client.write(byteToSend);
});
client.on('error', err => {
console.log(`Error: ${err.message}`);
})
});
server.listen(PORT, HOST, () => {
console.log("server started");
});
I have a service where clients subscribe to a socket connection and listens for updates coming down the pipeline. Once a client has subscribed to a room we send a sendSyncRequest (view below) which calls another service to grab any updated data and it publishes it back down the client through the socket room.
The issue that keeps popping comes when the socket.io version was updated from v1.7.3 to v2.1.1. After deploying the service to a production server everything goes a bit haywire and we start seeing a getaddrinfo ENOTFOUND error that pops up everytime sendSyncRequest gets hit.
Some additional information:
OS Version: Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-74-generic x86_64)
Node Version: 4.4.0
Socket.io Version: 2.2.1
Request Version: 2.81.0
Error screenshot:
getadrrinfo ENOTFOUND error
sendSyncRequest Code:
function sendSyncRequest(service, accessToken, lastUpdate, socketId, method) {
var uri = service.scheme + '://' + service.host + ':' + service.port + service.path;
var options = {
uri: uri,
strictSSL: false,
timeout: NO_RESPONSE_TIMEOUT,
json: true,
headers: {
Authorization: 'Bearer ' + accessToken
}
};
if (method === 'get') {
options.qs = {
lastUpdate: lastUpdate,
socketId: socketId
};
} else {
options.body = {
lastUpdate: lastUpdate,
socketId: socketId
};
}
request[method || 'post'](options, function(err, response) {
if (err) {
log.error('sendSyncRequest', err);
return;
}
if (response.statusCode !== 200) {
log.error('sendSyncRequest %d %s', response.statusCode, http.STATUS_CODES[response.statusCode]);
return;
}
}
);}
Socket Server Code:
module.exports.init = function (callback) {
log.info('starting new Socket.IO server');
io.origins('*:*');
log.info('initializing socket.io server');
io.attach(server.getServer());
io.on('disconnect', function (socket) {
log.info('socket.io server disconnect ', socket);
});
io.on('connection', function (socket) {
log.info('new socket.io client %s#%s (%s) connection',
socket);
socket.emit('successful_connection', {socketId: socket.id});
socket.on('disconnecting', function () {
log.info('socket.io client %s#%s (%s) disconnecting',
socket.userData.user,
socket.userData.domain,
socket.id);
for (var room in socket.rooms) {
if (socket.rooms.hasOwnProperty(room)) {
var count = io.sockets.adapter.rooms[room].length;
log.debug('current room %s connected client count = %d', room, count);
if (count <= 1) {
log.info('unsubscribing from room %s', room);
cacheClient.unsubscribe(room);
}
}
}
});
});
};
We have also looked into the following github issues which talks about the file descriptor limits, but ultimately this feels like a short term solution.
https://github.com/nodejs/node-v0.x-archive/issues/5545#issuecomment-19007785
https://github.com/nodejs/node-v0.x-archive/issues/5488
If anyone has any suggestions or fixes, please share, we welcome all the help we can get.
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);
});
});