node-websocket-server:可能有多个独立的“广播”为一个node.js进程?

我想知道是否有可能在同一个节点websocket服务器应用程序实例运行不同的websocket“连接”广播。 设想一个聊天室服务器有多个房间,只在一个node.js服务器进程中向每个房间的特定参与者发送消息。 我已经成功地实现了一个单一聊天室的解决scheme,但我想把它提升到一个新的水平。

你可能会喜欢尝试Push-it: http ://github.com/aaronblohowiak/Push-Itbuild立在Socket.IO之上。 devise遵循Bayeux协议。

不过,如果你需要使用redis pubsub的东西,你可以查看http://github.com/shripadk/Socket.IO-PubSub

具体回答你的问题:你可以维护连接到websocket服务器的所有客户端的数组。 也许只是广播给这些客户的一个子集? 广播方法基本上是在引擎盖下。 node-websocket-server / Socket.IO维护一个连接的所有客户端的数组,并通过它们的每一个“发送”消息到每个客户端。 代码的要点:

// considering you storing all your clients in an array, should be doing this on connection: clients.push(client) // loop through that array to send to each client Client.prototype.broadcast = function(msg, except) { for(var i in clients) { if(clients[i].sessionId !== except) { clients[i].send({message: msg}); } } } 

因此,如果您只想将消息中继到特定的频道,只需保留客户端订阅的所有频道的列表。 这里是一个简单的例子(只是让你开始):

 clients.push(client); Client.prototype.subscribe = function(channel) { this.channel = channel; } Client.prototype.unsubscribe = function(channel) { this.channel = null; } Client.prototype.publish = function(channel, msg) { for(var i in clients) { if(clients[i].channel === channel) { clients[i].send({message: msg}); } } } 

为了更容易使用EventEmitter。 因此,在node-websocket-server / Socket.IO中查看接收消息的位置,并根据消息typesparsing消息以检查消息的types(订阅/取消订阅/发布)并发送消息。 例:

 Client.prototype._onMessage = function(message) { switch(message.type) { case 'subscribe': this.emit('subscribe', message.channel); case 'unsubscribe': this.emit('unsubscribe', message.channel); case 'publish': this.emit('publish', message.channel, message.data); default: } } 

聆听('连接')应用程序中发出的事件:

 client.on('subscribe', function(channel) { // do some checks here if u like client.subscribe(channel); }); client.on('unsubscribe', function(channel) { client.unsubscribe(channel); }); client.on('publish', function(channel, message) { client.publish(channel, message); }); 

希望这可以帮助。

在创build其他答案时,我不确定房间是否是一个function,但在文档中,它们具有您正在查找的function。 所以去那个链接,searchrooms

这里是一个来自网站的例子:

 var io = require('socket.io').listen(80); io.sockets.on('connection', function (socket) { socket.join('justin bieber fans'); socket.broadcast.to('justin bieber fans').emit('new fan'); io.sockets.in('rammstein fans').emit('new non-fan'); }); 

基于其他的答案,它更侧重于缩放,如果内置版本的比例和所提出的答案一样好的话,我会非常期待。

Shripad K的答案非常有条理。 做得好。

我认为这个解决scheme虽然会有一些扩展问题。

如果您在500个聊天室中有10,000个并发用户,则每当有用户发送消息时,您都必须遍历所有10,000个客户端。 我怀疑将这个客户列表存储在一个redis结构中的某个特定的房间中会更快,并且只需要抓取这个列表并发送给这些客户。

1)不确定这是否更快。 2)不知道什么可以存储在redis,然后让我们参考客户端。 也许可以有一个散列在服务器中的所有客户端,通过一个唯一的id和redis,我们可以只存储一组用户ID每个聊天室?

这似乎有更多的可扩展性?

我已经写了一个基于fzysqr的节点聊天服务器,并且在我们广泛推广之前,需要使它可以扩展为多个聊天。

与房间我简单的testing聊天看起来像

chat.js:

 var app = require('http').createServer(handler) , io = require('socket.io').listen(app) , fs = require('fs') app.listen(80); function handler (req, res) { fs.readFile(__dirname + '/chat.html', function (err, data) { if (err) { res.writeHead(500); return res.end('Error loading chat.html'); } res.writeHead(200); res.end(data); }); } io.sockets.on('connection', function (socket) { socket.on('join', function (room) { if (Array.isArray(room)) { var i; for (i = 0; i < room.length; ++i) { console.log('join room ' + room[i]); socket.join(room[i]); } } else if (typeof room === 'string') { console.log('join room ' + room); socket.join(room); } }); socket.on('leave', function (room) { if (typeof room === 'string') { console.log('leave room ' + room); socket.leave(room); } }); socket.on('post', function (data) { io.sockets.in(data.room).emit('publish', data); }); }); 

和chat.html:

 <html> <head> <title>Node js test</title> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script> <script src="http://127.0.0.1:80/socket.io/socket.io.js"></script> </head> <body> <h2>Node js test</h2> <div style="height:400px;"> <div id="controls" style="height:400px; display: inline-block; width:20%; float:left; background-color:lightyellow;"> <input id="room1_check" type="checkbox" value="room_1" checked /><label for="room1_check">Room 1</label><br/><br/> <input id="room2_check" type="checkbox" value="room_2" /><label for="room2_check">Room 2</label><br/><br/> <input id="room3_check" type="checkbox" value="room_3" checked /><label for="room3_check">Room 3</label><br/><br/> <input id="room4_check" type="checkbox" value="room_4" /><label for="room4_check">Room 4</label><br/><br/> <input id="room5_check" type="checkbox" value="room_5" /><label for="room5_check">Room 5</label><br/><br/> </div> <div id="stream" style="height:400px; display: inline-block; width:40%; background-color:white; overflow:auto;"></div> <div id="post" style="height:400px; display: inline-block; width:40%; float:right; background-color:yellow;"> <label for="postRoom">Room: </label> <select id="postToRoom"> <option value="room_1">Room 1</option> <option value="room_2">Room 2</option> <option value="room_3">Room 3</option> <option value="room_4">Room 4</option> <option value="room_5">Room 5</option> </select> <br/><br/> <label for="postBy">By: </label> <select id="postBy"> <option value="User 1">User 1</option> <option value="User 2">User 2</option> <option value="User 3">User 3</option> <option value="User 4">User 4</option> <option value="User 5">User 5</option> </select> <br/><br/> <label for="postMessage">Message:</label><br/> <textarea id="postMessage" style="width:80%; height:100px;" ></textarea> <br/><br/> <input id="postBtn" type="button" value="post message" /> </div> </div> <script> var socket = io.connect('http://127.0.0.1:80'); var checkedRooms = []; $('#controls :checked').each(function() { checkedRooms.push($(this).val()); }); socket.emit('join', checkedRooms); socket.on('publish', function (post) { //console.log(data); $("#stream").html($("#stream").html() + "room: " + post.room + "<br/>"); $("#stream").html($("#stream").html() + "by: " + post.by + "<br/>"); $("#stream").html($("#stream").html() + "on: " + post.on + "<br/>"); $("#stream").html($("#stream").html() + "message: " + unescape(post.message) + "<br/>"); $("#stream").html($("#stream").html() + "=============================================<br/>"); }); $('#controls :checkbox').change(function () { socket.emit(this.checked ? 'join' : 'leave', $(this).val()); }); $("#postBtn").click(function() { socket.emit('post', {room: $("#postToRoom").val(), message: escape($("#postMessage").val()), by: $("#postBy").val(), on: (new Date() + "") }); }); </script> </body> </html>