I have a socket based server that uses Einaros WS on Node JS. I think my question applies regardless of the socket library choice. Currently, whenever I get a new connection I store each socket object in an array like this:
var WebSocketServer = require("ws").Server;
...
var server = require('http').createServer(app);
...
var wss = new WebSocketServer({server: server});
var clients = [];
wss.on("connection", function(ws) {
console.log("websocket connection open");
ws.on("message", function(message) {
{
message = JSON.parse(message);
switch (message.type) {
case "START":
{
ws.user_id = message.user_id;
clients[ws.user_id]=ws;
}
...
This means for each open connection I am storing what I believe to be a fairly large socket object. Is there a way to store an identifier or pointer to this object instead of storing the entire socket in an array this way? How do systems that can handle a very large number of open connections store / remember open sockets?
The "ws" variable is just a reference to the websocket object, not a copy of the structure, so it is no more expensive than storing any other object (or primitive) in an array.
It is better to store socket IDs in REDIS as it will help when you will scale your application and your socket servers will be on different machines.
Related
I have a single device establishing two WebSocket connections to the Einaros/ws WebSocket server. Whenever the second WebSocket connection sends a message to the server, only the first websocket.on("message") event emitter responds. There is no way to differentiate which WebSocket the message is coming from because there seems to be only a single websocket.on("message") event emitter object.
How can I differentiate from which WebSocket connection the message is being received from without passing an ID from the client side?
I apologize if I am overlooking something simple, I am a node.js and coding novice. From the code below it looks like there should be separate event emitter objects created for each WebSocket connection so that the server knows which connection the message is coming from. My code looks like this:
var connections = new Map();
var idCounter = 0;
wss.on("connection", function connection(ws) {
var connectionID = idCounter++;
connections.set(connectionID, ws);
var session = connections.get(connectionID);
session.on("message", function incoming(message) {
session.send(message);
}
}
--- Update ---
I have performed another test. With the code below "objectTest" contains the unique WebSocket connection distinguished by 'sec-websocket-key' printed to the console. However "this.send(message);" and "console.log(this);" both refer to the first established WebSocket connection even while "objectTestMap" contains the second "objectTest" that is unique.
var connections = new Map();
var idCounter = 0;
wss.on("connection", function connection(ws) {
var connectionID = idCounter++;
connections.set(connectionID, ws);
var session = connections.get(connectionID);
var sendThis = String(connectionID);
session.send(sendThis);
var objectTestMap = new Map();
var objectTest = session.on("message", function incoming(message) {
this.send(message);
console.log(this);
});
objectTestMap.set(connectionID, objectTest);
console.log(objectTestMap.get(connectionID));
});
Their was an error on my client application that was connecting to the server. No problems with WS and the above code works as it should.
I'm using the ws module here.
And to reference the socket connections to a global users object is done like so:
users = {}
var WebSocketServer = require('ws').Server, wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function connection(socket) {
users[2] = {
name: 'Bob',
clientID: socket
}
});
Now, if we want to utilize this socket object that is reference to this user, we can do:
users[2].clientID.send('Hello from client ID 2');
And this will work inside the current nodejs process of which it was made.
My problem is, when sending this data through the ipc or storing this data to redis or memcache, there is no way to reference that socket back to this specific user.
For IPC, nodejs JSON.stringify's the object, and with redis and memcache it stores it as key value string pairs as well.
If I wanted to transfer this object (with the socket referenced) to another child process to be used, how can that be done?
I'm looking to build a node app that will accomplish the following:
Open several websocket connections, almost as if each of them were a
thread
Allow each websocket to have a unique/dynamic URL
Create a pool of websocket connections in an object based off some kind of DB query (so I can dynamically add/remove connections)
I've decided to use the ws library (https://github.com/websockets/ws) since its the fastest and least bloated option available. I currently have the following function, which only supports a single ws connection:
chat.prototype.connect = function() {
var self = this;
self.ws = new ws(url);
self.ws.on('message', function(data, flags) {
var message = JSON.parse(data);
self.handle(message);
});
};
This code listens to a single websocket URL and passes the message(s) to my handler to process the message. Instead, I want to make this function listen to multiple (potentially hundreds) of websocket URL's.
Does anyone have some ideas on how to accomplish this?
Say that you have the list of url's you need to connect to stored in an instance property called urls. You could set up the connections like this:
chat.prototype.connect = function() {
urls.forEach(this.connectOne.bind(this));
};
chat.prototype.connectOne = function(url) {
var handle = this.handle.bind(this);
var conn = this.connections[url] = new ws(url);
conn.on('message', function(data, flags) {
var message = JSON.parse(data);
handle(message);
});
};
To implement adding new connections, periodically query your database and check if each URL is already present in this.connections; if not, you can use this.connectOne() to add it. You'd do something similar to remove a connection.
I'm trying to implement a TCP proxy in Node JS. I only have some experience with Javascript so I met a lot of problems along the way. I've done a lot of searching for this one but had no luck.
The problem occurs when browser sends a CONNECT request for HTTPS. My proxy will parse the host name and port, and then create a new socket that connects to the server. If all these steps went well, I will start forwarding message.
Part of my code looks like this:
var net = require('net');
var server = net.createServer(function(clientSock) {
clientSock.on('data', function(clientData) {
var host = // get from data
var port = // get from data
if (data is a CONNECT request) {
// Create a new socket to server
var serverSock = new net.Socket();
serverSock.connect(port, host, function() {
serverSock.write(clientData);
clientSock.write('HTTP/1.1 200 OK\r\n');
}
serverSock.on('data', function(serverData) {
clientSock.write(serverData);
}
}
}
}
Since the CONNECT request needs both client socket and server socket open until one side closes the connection, the code above doesn't have this behavior. Every time I receive some data from client, I will create a new socket to server and the old one is closed.
Is there a way to store the server socket as a global variable so that the data event handler can reuse it? Or is there any other way to solve this?
Thanks a lot!!!!
You can just move the variable up to a higher scope so it survives across multiple events and then you can test to see if its value is already there:
var net = require('net');
var server = net.createServer(function(clientSock) {
var serverSock;
clientSock.on('data', function(clientData) {
var host = // get from data
var port = // get from data
if (data is a CONNECT request) {
// Create a new socket to server
if (!serverSock) {
serverSock = new net.Socket();
serverSock.connect(port, host, function() {
serverSock.write(clientData);
clientSock.write('HTTP/1.1 200 OK\r\n');
}
serverSock.on('data', function(serverData) {
clientSock.write(serverData);
}
} else {
serverSock.write(clientData);
}
}
}
}
I create a server with Node.js:
var net = require('net');
var PORT = 8181;
var server = net.createServer(
function(socket) {
console.log(this.address());
socket.on('data', function(data) {
var msg = data.toString().replace(/\n$/, '');
console.log('got: ' + msg);
});
process.stdin.on('readable',
function() {
var chunk = process.stdin.read();
if (chunk !== null) {
socket.write(chunk);
}
}
)
socket.write('heyyo\n');
}
)
Now, when multiple connections are coming in, this server sends out the typed in line only to the first connection.
I have two questions:
what is a standard way to handle this, i.e. to store the incoming sockets into an array?
exactly what happens that causes the readable event not to reach the other connections' callback function?
I would highly recommend using a library like socket.io. It makes handling connect/disconnect as well as placing sockets in rooms very simple. Additionally you can get the full list of available rooms and connected sockets through the adapter class it offers. A functional example is available in the docs.