web-dev-qa-db-fra.com

Envoyer un message à un client spécifique avec socket.io et node.js

Je travaille avec socket.io et node.js et jusqu'à présent, cela semble assez bon, mais je ne sais pas comment envoyer un message du serveur à un client spécifique, quelque chose comme ceci:

client.send(message, receiverSessionId)

Mais ni les méthodes .send() ni .broadcast() ne semblent répondre à mes besoins.

Ce que j’ai trouvé comme solution possible, c’est que la méthode .broadcast() accepte comme second paramètre un tableau de SessionIds auquel ne pas envoyer le message, afin que je puisse passer un tableau avec tous les SessionIds connectés à serveur, sauf celui que je souhaite envoyer le message, mais j'estime qu'il doit y avoir une meilleure solution.

Des idées?

173
Rodolfo Palma

Eh bien, vous devez prendre le client pour cela (surprise), vous pouvez soit aller de la manière la plus simple:

var io = io.listen(server);
io.clients[sessionID].send()

Ce qui peut casser, j'en doute à peine, mais il est toujours possible que io.clients soit modifié, utilisez donc ce qui précède avec prudence.

Ou vous gardez une trace des clients vous-même, vous les ajoutez donc à votre propre objet clients dans l'écouteur connection et les supprimez dans l'écouteur disconnect.

J'utiliserais ce dernier, car en fonction de votre application, vous voudrez peut-être avoir plus d'état sur les clients, donc quelque chose comme clients[id] = {conn: clientConnect, data: {...}} pourrait faire l'affaire.

90
Ivo Wetzel

La réponse d'Ivo Wetzel ne semble plus être valable dans Socket.io 0.9.

En bref, vous devez maintenant enregistrer le socket.id et utiliser io.sockets.socket(savedSocketId).emit(...) pour lui envoyer des messages.

Voici comment cela fonctionne dans le serveur en cluster Node.js:

Vous devez d’abord définir le magasin Redis en tant que magasin pour que les messages puissent passer d’un processus à un autre:

var express = require("express");
var redis = require("redis");
var sio = require("socket.io");

var client = redis.createClient()
var app = express.createServer();
var io = sio.listen(app);

io.set("store", new sio.RedisStore);


// In this example we have one master client socket 
// that receives messages from others.

io.sockets.on('connection', function(socket) {

  // Promote this socket as master
  socket.on("I'm the master", function() {

    // Save the socket id to Redis so that all processes can access it.
    client.set("mastersocket", socket.id, function(err) {
      if (err) throw err;
      console.log("Master socket is now" + socket.id);
    });
  });

  socket.on("message to master", function(msg) {

    // Fetch the socket id from Redis
    client.get("mastersocket", function(err, socketId) {
      if (err) throw err;
      io.sockets.socket(socketId).emit(msg);
    });
  });

});

J'ai omis le code de regroupement ici, car cela le rend plus encombré, mais il est trivial d'ajouter. Ajoutez simplement tout au code de l'ouvrier. Plus de documents ici http://nodejs.org/api/cluster.html

169
Epeli

chaque socket rejoint une pièce avec un identifiant de socket pour un nom, vous pouvez donc

io.to(socket#id).emit('hey')

docs: http://socket.io/docs/rooms-and-namespaces/#default-room

À votre santé

86
Matic Kogovšek

La solution la plus simple et la plus élégante

C'est aussi simple que:

client.emit("your message");

Et c'est tout.

Mais comment? Donne moi un exemple

Ce dont nous avons tous besoin est en fait un exemple complet, et c'est ce qui suit. Ceci est testé avec la version la plus récente de socket.io (2.0.3) et utilise également le Javascript moderne (que nous devrions tous utiliser maintenant).

L'exemple comprend deux parties: un serveur et un client. Lorsqu'un client se connecte, il commence à recevoir du serveur un numéro de séquence périodique. Une nouvelle séquence est lancée pour chaque nouveau client. Le serveur doit donc les suivre individuellement. C'est là que le "je dois envoyer un message à un client particulier" entre en jeu. Le code est très simple à comprendre. Voyons ça.

Serveur

server.js

const
    io = require("socket.io"),
    server = io.listen(8000);

let
    sequenceNumberByClient = new Map();

// event fired every time a new client connects:
server.on("connection", (socket) => {
    console.info(`Client connected [id=${socket.id}]`);
    // initialize this client's sequence number
    sequenceNumberByClient.set(socket, 1);

    // when socket disconnects, remove it from the list:
    socket.on("disconnect", () => {
        sequenceNumberByClient.delete(socket);
        console.info(`Client gone [id=${socket.id}]`);
    });
});

// sends each client its current sequence number
setInterval(() => {
    for (const [client, sequenceNumber] of sequenceNumberByClient.entries()) {
        client.emit("seq-num", sequenceNumber);
        sequenceNumberByClient.set(client, sequenceNumber + 1);
    }
}, 1000);

Le serveur commence à écouter le port 8000 pour les connexions entrantes. Quand on arrive, il ajoute ce nouveau client à une carte afin qu’il puisse garder une trace de son numéro de séquence. Il écoute également l'événement disconnect de ce client lorsqu'il le supprime de la carte.

Chaque seconde, une minuterie est déclenchée. Lorsque cela se produit, le serveur parcourt la carte et envoie un message à chaque client avec son numéro de séquence actuel. Il l'incrémente ensuite et enregistre le numéro dans la carte. C'est tout ce qui s'y passe. Peasy facile.

Client

La partie client est encore plus simple. Il se connecte simplement au serveur et écoute le message seq-num, en l'imprimant sur la console à chaque fois qu'il arrive.

client.js

const
    io = require("socket.io-client"),
    ioClient = io.connect("http://localhost:8000");

ioClient.on("seq-num", (msg) => console.info(msg));

Exécuter l'exemple

Installez les bibliothèques requises:

npm install socket.io
npm install socket.io-client

Exécutez le serveur:

node server

Ouvrez d'autres fenêtres de terminal et créez autant de clients que vous le souhaitez en exécutant:

node client

J'ai également préparé un Gist avec le code complet ici .

74
Lucio Paiva

En 1.0, vous devriez utiliser:

io.sockets.connected[socketid].emit();
33
PHPthinking

Vous pouvez utiliser

// envoie le message uniquement à l'expéditeur-client

socket.emit('message', 'check this');

// ou vous pouvez envoyer à tous les auditeurs, y compris l'expéditeur

io.emit('message', 'check this');

// envoyer à tous les auditeurs sauf l'expéditeur

socket.broadcast.emit('message', 'this is a message');

// ou tu peux l'envoyer dans une chambre

socket.broadcast.to('chatroom').emit('message', 'this is the message to all');

29
DecoderNT

Quelle que soit la version que nous utilisons si nous ne faisons que console.log (), l’objet "io" que nous utilisons dans notre code nodejs côté serveur, [par exemple. io.on ('connexion', fonction (socket) {...});], nous pouvons voir que "io" est juste un objet json et qu'il existe de nombreux objets enfants dans lesquels les identifiants de socket et les objets de socket sont stockés.

J'utilise socket.io version 1.3.5, d'ailleurs.

Si nous regardons dans l'objet io, il contient,

 sockets:
  { name: '/',
    server: [Circular],
    sockets: [ [Object], [Object] ],
    connected:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },

ici nous pouvons voir les socketids "B5AC9w0sYmOGWe4fAAAA" etc. Donc, nous pouvons faire,

io.sockets.connected[socketid].emit();

Encore une fois, lors d’une inspection plus poussée, nous pouvons voir des segments tels que,

 eio:
  { clients:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },

Donc, nous pouvons récupérer un socket d’ici en faisant

io.eio.clients[socketid].emit();

En outre, sous moteur nous avons,

engine:
 { clients:
    { B5AC9w0sYmOGWe4fAAAA: [Object],
      'hWzf97fmU-TIwwzWAAAB': [Object] },

Donc, on peut aussi écrire,

io.engine.clients[socketid].emit();

Donc, je suppose que nous pouvons atteindre notre objectif de l’une des 3 manières que j’ai énumérées ci-dessus,

  1. io.sockets.connected [socketid] .emit (); OU
  2. io.eio.clients [socketid] .emit (); OU
  3. io.engine.clients [socketid] .emit ();
12
Suman Barick

Tu peux le faire

Sur le serveur.

global.io=require("socket.io")(server);

io.on("connection",function(client){
    console.log("client is ",client.id);
    //This is handle by current connected client 
    client.emit('messages',{hello:'world'})
    //This is handle by every client
    io.sockets.emit("data",{data:"This is handle by every client"})
    app1.saveSession(client.id)

    client.on("disconnect",function(){
        app1.deleteSession(client.id)
        console.log("client disconnected",client.id);
    })

})

    //And this is handle by particular client 
    var socketId=req.query.id
    if(io.sockets.connected[socketId]!=null) {
        io.sockets.connected[socketId].emit('particular User', {data: "Event response by particular user "});
    }

Et sur le client, il est très facile à manipuler.

var socket=io.connect("http://localhost:8080/")
    socket.on("messages",function(data){
        console.log("message is ",data);
        //alert(data)
    })
    socket.on("data",function(data){
        console.log("data is ",data);
        //alert(data)
    })

    socket.on("particular User",function(data){
        console.log("data from server ",data);
        //alert(data)
    })
11
abhaygarg12493

A partir de la version 1.4.5, assurez-vous de fournir un socketId avec le préfixe approprié dans io.to (). Je prenais le socketId le client connecté pour déboguer et c'était sans préfixe alors j'ai fini par chercher pour toujours jusqu'à ce que je le découvre! Donc, vous devrez peut-être le faire comme ceci si l'identifiant que vous avez n'est pas préfixé:

io.to('/#' + socketId).emit('myevent', {foo: 'bar'});
6
risuch

io.sockets.sockets [socket.id] .emit (...) a travaillé pour moi dans la v0.9

4
aljosa

Socket.IO vous permet de "nommer" vos sockets, ce qui signifie essentiellement assigner différents points de terminaison ou chemins.

Cela pourrait aider: http://socket.io/docs/rooms-and-namespaces/

0
Igor T.