Is it possible to send a message to all active WebSocket connections? Using either node.js or python tornado websockets
socket.io solution:
// note, io.listen() will create a http server for youvar io = require('socket.io').listen(80);io.sockets.on('connection', function (socket) { io.sockets.emit('this', { will: 'be received by everyone' }); socket.on('private message', function (msg) { console.log('I received a private message from ', socket.id, ' saying ', msg); // Echo private message only to the client who sent it socket.emit('private message', msg); }); socket.on('disconnect', function () { // This will be received by all connected clients io.sockets.emit('user disconnected'); });});all_active_connections = {};
webocket server (there are many), do same manually:
var ws = require("ws"); global_counter = 0; all_active_connections = {}; ws.createServer(function (websocket) { websocket.on('connect', function() { var id = global_counter++; all_active_connections[id] = websocket; websocket.id = id; }).on('data', function (data) { if (data == 'broadcast me!') { for (conn in all_active_connections) all_active_connections[conn].write(data); } } }).on('close', function() { delete all_active_connections[websocket.id]; }); }).listen(8080);
For a solution based on tornado/tornadio, you SocketConnection class needs to maintain a list of connections at the class level. Your on_connect handler would add the connection to this list, and on_close would remove it. For sample pseudo-code see this post by Serge S. Koval. The code is reproduce below:
Declare your TornadIO connection class:
class MyConnection(SocketConnection): participants = set() @classmethod def broadcast(cls, msg): for p in cls.participants: p.send(msg) @classmethod def controller_msg(cls, msg): cls.broadcast(msg)
In your device polling thread, do something like:
while True: datum = file.readline() if len(datum) > 2: t = json.loads(datum) ... def callback(): MyConnection.controller_msg(t) io_loop.add_callback(callback)
Additionally, gevent-socketio has support for message broadcast, but it's based on gevent, not tornado.
UPDATE:
tornadio2 already maintains a list of active sessions, so all you need to do is:
class MyConnection(SocketConnection): def broadcast(self, event, message): for session_id, session in self.session.server._sessions._items.iteritems(): session.conn.emit(event, message)
This works because each connection instance has a reference to its session, which has a reference to the global router used to create the application (stored as server
), which maintains a list of sessions in a SessionContainer
object in _sessions
. Now whenever you want to broadcast a message within your connection class, just do:
self.broadcast('my_custom_event', 'my_event_args')
This redis + websockets (on tornado) example should help you. Basically you have a list of listeners who should be notified and as soon as a message is received iterate through that list and inform them.