How send message on websocket server to specific user( s) - node.js

I'm reading up on websockets and after reading a lot of tutorials and blogs (mostly about creating a simple chat application) there is still 1 question unanswered :
Type of technology used aside (node.js or php of python) I find no way of sending a message to 1 user or a group of users without first getting an event of the client to the websocket server ( often called onconnect() or onmessage() ).
Is it then not possible to have some external application or event call some script (bash or php) that uses the existing running websocket instance to send/broadcast some information (text) to one or more connected browsers (websocket clients) ??
Sorry if this is a stupid question but I am not able to find an answer by reading these blogs on the web.
Thank you for this clarification.

From what I've understand, you can easily use sockets like:
// main.js
this.sockets = {};
myOtherModule.init(sockets);
io.on('connection', function(socket)) {
sockets[socket.id] = socket;
socket.on('command', myOtherModule.onSocketCommand);
}
// myOtherModule.js
this.init = function(sockets) {
this.sockets = sockets;
}
this.onSocketCommand = function() {
this.sockets['other.socket.id'].emit('message');
}
You can always save the socket somewhere, no matter if it's within object or single variable. Then you can always use it to emit messages.

Related

Is there a better solution than socket.io for slow-speed in-game chat?

I am creating a browser game with node.js (backend api) and angular (frontend). My goal is to implement an in-game chat to allow communication between players on the same map. The chat is not an essential part of the game, so messages don't need to be instant (few seconds of latency should be ok). It is just a cool feature to talk some times together.
A good solution should be to implement socket.io to have real-time communication. But as chat is not an essential component and is the only thing which will require websockets, i'm wondering if there is not an alternative to avoid server overload with sockets handling.
I thinked about polling every 2 or 3 seconds my REST API to ask for new messages, but it may overload server the same way... What are your recommandations?
Thank you for your advices
There's a pretty cool package called signalhub. It has a nodejs server component and stuff you can use in your users' browsers. It uses a not-so-well-known application of the http (https) protocol called EventSource. EventSource basically opens persistent http (https) connections to a web server.
It's a reliable and lightweight setup. (The README talks about WebRTC signalling, but it's useful for much more than that.)
On the server side, a simple but effective server setup might look like this:
module.exports = function makeHubServer (port) {
const signalhubServer = require('signalhub/server')
const hub = signalhubServer({ maxBroadcasts: 0 })
hub.on('subscribe', function (channel) {
/* you can, but don't have to, keep track of subscriptions here. */
})
hub.on('publish', function (channel, message) {
/* you can, but don't have to, keep track of messages here. */
})
hub.listen(port, null, function () {
const addr = hub.address()
})
return hub
}
In a browser you can do this sort of thing. It user GET to open a persistent EventSource to receive messages. And, when it's time to send a message, it POSTs it.
And, Chromium's devtools Network tab knows all about EventSource connections.
const hub = signalhub('appname', [hubUrl])
...
/* to receive */
hub.subscribe('a-channel-name')
.on('data', message => {
/* Here's a payload */
console.log (message)
})
...
/* to send */
hub.broadcast('a-channel-name', message)

I either don't get any messages from a web socket (socket.io), or occasionally I get them all at once (but not always)

When I start my server, I get 1 response from the web socket that shows information about bitcoin but I either never get updates whenever the price changes or I suddenly get loads of updates. I assume I should be getting a new message every second or so. I'm using this web socket https://www.cryptocompare.com/api/#-api-web-socket-current-
Here's my code:
var ioClient = require('socket.io-client');
var cryptocompare = ioClient.connect('wss://streamer.cryptocompare.com')
var subscription = '2~Poloniex~BTC~USD';
cryptocompare.emit('SubAdd', { subs: [subscription] });
cryptocompare.on('error', console.error)
cryptocompare.on('m', function(message) {
console.log(message);
});
In the first instance I would very strongly encourage you to use the Tidwall websockets library
https://github.com/tidwall/SwiftWebSocket
It's incredibly well-written, it's one of the best libraries of any type out there.
Again in the first instance, you'll struggle to know what is going on, until you are using a rock-solid library ...

Connecting to socket.io 1.x manually using websockets, capacity testing

I am working with a nodejs express server which uses socket.io to communicate an iOS client, and am having a little trouble trying to test how many clients can connect and exchange data at any one time.
My goal is to be able to run a script which connects to socket.io with thousands of different sessions, as well as send and receive data to understand our system's scale. Currently we are using a single dyno on Heroku but will likely be considering other options on AWS soon.
I have found code which should do what I am trying to do for earlier versions of socket.io, such as this, but have had issues since it seems v1.x has a very different handshake protocol. I tried out using the socket.io-client package, but trying to connect multiple times only simulates use of one session, I need to simulate many in independent users.
I have been picking apart the socket.io-client code, but have only gotten so far as creating a connection - I am stuck on the sending data part. If anyone has any knowledge or could point to some written resources on how data is sent between a client and a socket.io server, it would help me out a lot.
Here's what I have so far:
var needle = require('needle'),
WebSocket = require('ws'),
BASE_URL = 'url-to-socket-host:5002';
var connectionNo = 0;
needle.get('http://' + BASE_URL + '/socket.io/?EIO=3&transport=polling&t=1416506501335-0', function (err, resp) {
// parse the sid
var resp = JSON.parse(resp.body.toString().substring(5, resp.body.toString().length));
// use the sid to connect using websockets
var url = 'ws://' + BASE_URL + '/socket.io/?EIO=3&transport=websocket&sid=' + resp.sid;
console.log(connectionNo + ' with sid: ' + resp.sid);
var socket = new WebSocket(url, void(0), {
agent: false
});
socket.on('open', function () {
console.log('Websocket connected: ' + connectionNo);
// I don't understand how to send data to the server here,
// from looking at the source code it should use some kind
// of binary encoding, any ideas?
socket.on('message', function (msg) {
console.log(msg);
});
});
});
I will continue deconstructing the socket.io-client code but if anyone has any clues or recourses that may help, let me know. Thanks.
I ended up setting for using the socket.io-client npm package which has the ability to connect to a new session on every connection. I found an example benchmark in this issue.
There is not so much need for me to manually connect to socket.io using pure websockets and HTTP, but thanks to Yannik for pointing out the parser in use. The spec of the inner workings of v1.x can be found here.
Thanks!
The problem my reside in the fact that you are not using socket.io in your client code. You have imported ('ws') which is another module whose docs are here: https://www.npmjs.org/package/ws.
You probably want to ws.send('something');. When you receive a message in ws, it also comes with an object with a property indicating whether it is binary data or not. If it is, you will need to concatenate the chunks incrementally. There is a canonical way to do this which you can find via google. But it looks a little like this:
var message;
socketConnection.on('data', function(chunk){ message += chunk});

What's the correct way to pass a Socket.IO socket between modules?

At the moment I have a getter/setter socket module as follows
var socket;
module.exports.getSocket = getSocket;
module.exports.setSocket = setSocket;
function getSocket() {
return socket;
}
function setSocket(sock) {
if (undefined == socket) socket = sock;
}
In app.js I set as follows
var sio = require('./lib/socket');
var io = require('socket.io').listen(app);
io.sockets.on('connection', function (socket) {
sio.setSocket(socket);
});
In my module I use as follows
sio = require('./lib/socket');
socket.getSocket().broadcast.emit(...);
It seems a bit contrived is there a better way to do this?
Edit: I would like a general solution to the problem of firing off a message which is not initiated by the client socket. For example suppose I retrieve stock prices from an external source and wish to fire an event on price update. Since it is not client initiated, how can I get access to the socket? Or alternatively let's say I wish to fire off a socket message in response to a POST request. Once again I'm not sure how I would access the socket.
There are a number of options for sharing the socket, but it would help to know more about what your module is going to do. Without knowing more, I would recommend you just pass the socket to the module via the function you are calling instead of trying to use some shared state.
If you need to use a shared state (you're trying to send messages to specific users triggered by something other than a socket message) then I would recommend sticking with an established session framework and just persist the socket id. You can get the correct socket just using the id.
See this answer for how to use socket.io with sessions: socket.io and session?
Add some more details and I'll revise my answer.
UPDATE
If you are just trying to broadcast to everyone who is connected, you do not need a socket handle. From any module that references socket.io, you can call io.sockets.emit('stuff').

node.js + socket.io broadcast from server, rather than from a specific client?

I'm building a simple system like a realtime news feed, using node.js + socket.io.
Since this is a "read-only" system, clients connect and receive data, but clients never actually send any data of their own. The server generates the messages that needs to be sent to all clients, no client generates any messages; yet I do need to broadcast.
The documentation for socket.io's broadcast (end of page) says
To broadcast, simply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.
So I currently capture the most recent client to connect, into a variable, then emit() to that socket and broadcast.emit() to that socket, such that this new client gets the new data and all the other clients. But it feels like the client's role here is nothing more than a workaround for what I thought socket.io already supported.
Is there a way to send data to all clients based on an event initiated by the server?
My current approach is roughly:
var socket;
io.sockets.on("connection", function (s) {
socket = s;
});
/* bunch of real logic, yadda yadda ... */
myServerSideNewsFeed.onNewEntry(function (msg) {
socket.emit("msg", { "msg" : msg });
socket.broadcast.emit("msg", { "msg" : msg });
});
Basically the events that cause data to require sending to the client are all server-side, not client-side.
Why not just do like below?
io.sockets.emit('hello',{msg:'abc'});
Since you are emitting events only server side, you should create a custom EventEmitter for your server.
var io = require('socket.io').listen(80);
events = require('events'),
serverEmitter = new events.EventEmitter();
io.sockets.on('connection', function (socket) {
// here you handle what happens on the 'newFeed' event
// which will be triggered by the server later on
serverEmitter.on('newFeed', function (data) {
// this message will be sent to all connected users
socket.emit(data);
});
});
// sometime in the future the server will emit one or more newFeed events
serverEmitter.emit('newFeed', data);
Note: newFeed is just an event example, you can have as many events as you like.
Important
The solution above is better also because in the future you might need to emit certain messages only to some clients, not all (thus need conditions). For something simpler (just emit a message to all clients no matter what), io.sockets.broadcast.emit() is a better fit indeed.

Resources