Я хотел бы узнать, можно ли транслировать на разных "соединениях" веб-приложений, запущенных из того же приложения node-websocket-server. Представьте себе сервер чата с несколькими комнатами, только передавая сообщения участникам, специфичным для каждой комнаты, на одном сервере node.js. Я успешно реализовал одночасовое решение для каждого процесса, но хочу перейти на следующий уровень.
Node -websocket-server: возможно иметь несколько отдельных "трансляций" для одного процесса node.js?
Ответ 1
Вам бы хотелось попробовать Push-it: http://github.com/aaronblohowiak/Push-It, который построен поверх Socket.IO. Конструкция придерживается протокола 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});
}
}
}
Чтобы еще проще использовать EventEmitters. Таким образом, в node -websocket-server/Socket.IO см., Где принимаются сообщения, и проанализируйте сообщение, чтобы проверить тип (подписаться/отписаться/опубликовать) и испустить событие с сообщением в зависимости от типа. Пример:
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);
});
Надеюсь, что это поможет.
Ответ 2
Я не уверен, что комнаты были функцией, когда были созданы другие ответы, но в документации у них есть функция, ты ищешь. Поэтому перейдите по этой ссылке и выполните поиск rooms
.
Вот пример с сайта:
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');
});
Основываясь на других ответах, это было больше сосредоточено на масштабировании, я хотел бы получить некоторое представление, если встроенная версия будет хорошо масштабироваться, как и предлагаемые ответы.
Ответ 3
Ответ Shripad K очень хорошо структурирован. Хорошая работа.
Я думаю, что решение будет иметь проблемы с масштабированием.
Если у вас было 10 000 одновременных пользователей в 500 чатах, каждый раз, когда любой пользователь отправлял сообщение, вам нужно было бы перебрать все 10 000 клиентов. Я подозреваю, что быстрее будет хранить список клиентов в данной комнате в структуре redis и просто захватить этот список и отправить этим клиентам.
1) Не уверен, что это быстрее. 2) Не уверен, что можно было бы сохранить в redis, что позволило бы нам ссылаться на клиентов. Может быть, может быть хеш всех клиентов на сервере, с помощью уникального идентификатора и в redis, мы могли бы просто сохранить набор идентификаторов пользователя в чате?
Является ли это более масштабируемым?
Я написал чат-сервер node на основе fzysqr и должен сделать его масштабируемым для нескольких чатов, прежде чем выкладывать его широко.
Ответ 4
С комнатами мой простой тестовый чат выглядит
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>