Invia un messaggio a un client specifico con socket.io e node.js

Sto lavorando con socket.io e node.js e fino ad ora sembra abbastanza buono, ma non so come inviare un messaggio dal server a un client specifico, qualcosa del genere:

client.send(message, receiverSessionId) 

Ma né i .send() né i metodi .broadcast() sembrano soddisfare il mio bisogno.

Quello che ho trovato come una ansible soluzione, è che il metodo .broadcast() accetta come secondo parametro un array di SessionIds a cui non inviare il messaggio, così potrei passare un array con tutti i SessionIds connessi in quel momento al server , tranne quello che desidero inviare il messaggio, ma sento che ci deve essere una soluzione migliore.

Qualche idea?

Bene, devi afferrare il cliente per quello (sorpresa), puoi andare nel modo più semplice:

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

Che potrebbe rompersi, non ne dubito affatto, ma è sempre una possibilità che io.clients possa essere modificato, quindi usa il sopra con caucanvas

Oppure tieni traccia dei tuoi clienti, quindi li aggiungi al tuo object clients nel listener di connection e li rimuovi nel listener di disconnect .

Vorrei usare quest’ultimo, poiché a seconda dell’applicazione dovresti avere comunque uno stato più per i client, quindi qualcosa come i clients[id] = {conn: clientConnect, data: {...}} potrebbe fare il lavoro.

La risposta di Ivo Wetzel non sembra più valida in Socket.io 0.9.

In breve, ora è necessario salvare il socket.id e utilizzare io.sockets.socket(savedSocketId).emit(...) per inviare messaggi ad esso.

Ecco come ho ottenuto questo funzionamento nel server Node.js in cluster:

Per prima cosa è necessario impostare il negozio Redis come negozio in modo che i messaggi possano attraversare i processi:

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

Ho omesso il codice di cluster qui, perché rende questo più ingombrante, ma è banale da aggiungere. Basta aggiungere tutto al codice del lavoratore. Altri documenti qui http://nodejs.org/api/cluster.html

ogni socket unisce una stanza con un ID di socket per un nome, quindi puoi semplicemente

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

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

Saluti

La soluzione più semplice ed elegante

È facile come:

 client.emit("your message"); 

E questo è tutto.

Ma come? Fammi un esempio

Ciò di cui tutti abbiamo bisogno è in effetti un esempio completo, ed è quello che segue. Questo è testato con la versione più recente di socket.io (2.0.3) e sta anche usando il Javascript moderno (che dovremmo usare tutti ormai).

L’esempio è composto da due parti: un server e un client. Ogni volta che un client si connette, inizia a ricevere dal server un numero di sequenza periodica. Una nuova sequenza viene avviata per ogni nuovo client, quindi il server deve tenerne traccia individualmente. È qui che entra in gioco “Devo inviare un messaggio a un determinato cliente” . Il codice è molto semplice da capire. Vediamolo.

server

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

Il server inizia ad ascoltare sulla porta 8000 per le connessioni in entrata. Quando si arriva, aggiunge quel nuovo client a una mappa in modo che possa tenere traccia del suo numero di sequenza. Ascolta anche l’evento di disconnect quel cliente, quando lo rimuoverà dalla mappa.

Ogni secondo, viene triggersto un timer. Quando lo fa, il server cammina attraverso la mappa e invia un messaggio a ogni client con il suo numero di sequenza corrente. Quindi lo incrementa e memorizza il numero nella mappa. Questo è tutto. Vai tranquillo.

Cliente

La parte client è ancora più semplice. Si connette semplicemente al server e ascolta il messaggio seq-num , stampandolo sulla console ogni volta che arriva.

client.js

 const io = require("socket.io-client"), ioClient = io.connect("http://localhost:8000"); ioClient.on("seq-num", (msg) => console.info(msg)); 

Esecuzione dell’esempio

Installa le librerie richieste:

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

Esegui il server:

 node server 

Apri le altre windows del terminale e genera tutti i client che vuoi eseguendo:

 node client 

Ho anche preparato un sumrio con il codice completo qui .

In 1.0 dovresti usare:

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

Puoi usare

// invia un messaggio solo a mittente-cliente

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

// oppure puoi inviare a tutti gli ascoltatori incluso il mittente

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

// invia a tutti gli ascoltatori tranne il mittente

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

// oppure puoi inviarlo a una stanza

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

Qualunque versione usiamo se usiamo solo console.log () l’object “io” che usiamo nel nostro codice nodejs lato server, [eg io.on (‘connection’, function (socket) {…});] , possiamo vedere che “io” è solo un object json e ci sono molti oggetti figli in cui sono memorizzati gli oggetti socket e id.

Sto usando socket.io versione 1.3.5, btw.

Se guardiamo nell’object io, contiene,

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

qui possiamo vedere i socketid “B5AC9w0sYmOGWe4fAAAA” ecc. Quindi, possiamo fare,

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

Ancora una volta, su ulteriori ispezioni possiamo vedere segmenti come,

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

Quindi, possiamo recuperare un socket da qui facendo

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

Inoltre, sotto il motore abbiamo,

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

Quindi, possiamo anche scrivere,

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

Quindi, immagino che possiamo raggiungere il nostro objective in uno dei 3 modi che ho elencato sopra,

  1. io.sockets.connected [socketid] .emit (); O
  2. io.eio.clients [socketid] .emit (); O
  3. io.engine.clients [socketid] .emit ();

Puoi farlo

Sul server.

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

E sul client, è molto facile da gestire.

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

A partire dalla versione 1.4.5, assicurati di fornire un socketId prefissato correttamente in io.to (). Stavo prendendo il socket con il client registrato per il debug ed era senza prefisso quindi ho finito per cercare per sempre fino a quando ho scoperto! Quindi potresti doverlo fare così se l’ID che hai non è prefisso:

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

io.sockets.sockets [socket.id] .emit (…) ha funzionato per me in v0.9

Socket.IO ti permette di “namespace” i tuoi socket, il che significa essenzialmente l’assegnazione di diversi endpoint o percorsi.

Questo potrebbe aiutare: http://socket.io/docs/rooms-and-namespaces/