node-websocket-server: możliwe posiadanie wielu, oddzielnych "transmisji" dla jednego węzła.proces js?

Chciałbym wiedzieć, czy możliwe jest nadawanie na różnych WebSocket "connections" uruchomionych z tej samej instancji aplikacji node-websocket-server . Wyobraź sobie serwer czatu z wieloma pokojami, nadający tylko Wiadomości do uczestników specyficznych dla każdego pokoju, na jednym węźle.proces serwera js. Udało mi się wdrożyć rozwiązanie z jednym czatem na proces, ale chcę przenieść je na wyższy poziom.

Author: sawa, 2010-12-15

4 answers

Prawdopodobnie chciałbyś spróbować Push-it: http://github.com/aaronblohowiak/Push-It który zbudowany jest na Socket.IO. projekt jest zgodny z protokołem Bayeux.

Jeśli jednak potrzebujesz czegoś, co używa redis pubsub, możesz sprawdzić http://github.com/shripadk/Socket.IO-PubSub

Konkretnie odpowiadając na twoje pytanie: możesz utrzymywać tablicę wszystkich klientów podłączonych do serwera websocket. I pewnie po prostu nadawać do podgrupy tych klientów? Na Metoda transmisji robi to zasadniczo pod maską. node-websocket-server / Socket.IO utrzymuje tablicę wszystkich podłączonych klientów i po prostu zapętla wszystkie z nich"wyślij" wiadomość do każdego z klientów. Treść kodu:

// 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});
          }
      }
}

Więc jeśli chcesz przekazywać wiadomości tylko do określonych kanałów, po prostu zachowaj listę wszystkich kanałów subskrybowanych przez Klienta. Oto prosty przykład (na początek):

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});
         }
      }
}

Aby jeszcze bardziej ułatwić korzystanie z EventEmitters. Więc w node-websocket-server / Socket.IO sprawdza, gdzie wiadomości są odbierane i analizuje wiadomość, aby sprawdzić typ (subscribe/unsubscribe/publish) i emitować Zdarzenie z wiadomością w zależności od typu. Przykład:

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:

       }
}
W tym celu należy skontaktować się z Działem obsługi klienta.]}
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);
});
Mam nadzieję, że to pomoże.
 53
Author: Shripad Krishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 09:12:47

Nie jestem pewien, czy pokoje były funkcją podczas tworzenia innych odpowiedzi, ale w dokumentacji mają funkcję dokładnie tego, czego szukasz. Więc przejdź do tego linku i wyszukaj rooms.

Oto przykład ze strony:

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');
});

Bazując na innych odpowiedziach, bardziej skupiłem się na skalowaniu, chciałbym trochę wglądu, jeśli wbudowana wersja skaluje się dobrze jak proponowane odpowiedzi.

 27
Author: Shawn Mclean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-20 03:36:05

Odpowiedź Shripada K jest bardzo dobrze skonstruowana. Dobra robota.

Myślę, że to rozwiązanie będzie miało pewne problemy ze skalowaniem.

Gdybyś miał 10 000 jednoczesnych użytkowników na 500 czatach, to za każdym razem, gdy któryś z użytkowników wysłał wiadomość, musiałbyś przeszukiwać wszystkie 10 000 klientów. Podejrzewam, że szybciej byłoby zapisać listę klientów w danym pokoju w strukturze w redis i po prostu pobrać tę listę i wysłać do tych klientów.

1) Nie wiem, czy to rzeczywiście szybsze. 2) nie pewnie, co może być przechowywane w redis, co pozwoli nam odwoływać się do klientów. Może będzie hash wszystkich klientów na serwerze, przez unikalny identyfikator i w redis, moglibyśmy po prostu zapisać zestaw id użytkownika na czacie?

Czy to wydaje się bardziej skalowalne?

Napisałem serwer node chat oparty na fzysqr i muszę go skalować dla wielu czatów, zanim szeroko rozpowszechnimy.

 9
Author: Sean Colombo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-17 15:25:29

Z pokojami mój prosty czat testowy wygląda jak

Pogawędka.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);
    });

});


i rozmawiać.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>
 1
Author: Volodymyr Krupach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-06 15:06:16