javascript - rooms - socket.io example
Enviar mensaje a un cliente especĂfico con socket.io y node.js (11)
Estoy trabajando con socket.io y node.js y hasta ahora parece bastante bueno, pero no sé cómo enviar un mensaje desde el servidor a un cliente específico, algo como esto:
client.send(message, receiverSessionId)
Pero ni los .send()
ni .broadcast()
parecen satisfacer mi necesidad.
Lo que he encontrado como una posible solución, es que el método .broadcast()
acepta como un segundo parámetro una matriz de SessionIds a la cual no se envía el mensaje, por lo que podría pasar una matriz con todos los SessionIds conectados en ese momento al servidor , excepto el que deseo enviar el mensaje, pero creo que debe haber una mejor solución.
¿Algunas ideas?
La solución más simple y elegante
Es tan fácil como:
client.emit("your message");
Y eso es.
¿Pero cómo? Dame un ejemplo
Lo que todos necesitamos es, de hecho, un ejemplo completo, y eso es lo que sigue. Esto se prueba con la versión más reciente de socket.io (2.0.3) y también está utilizando Javascript moderno (que todos deberíamos usar ahora).
El ejemplo se compone de dos partes: un servidor y un cliente. Cada vez que un cliente se conecta, comienza a recibir del servidor un número de secuencia periódica. Se inicia una nueva secuencia para cada cliente nuevo, por lo que el servidor debe realizar un seguimiento de ellos de forma individual. Ahí es donde entra en juego el "Necesito enviar un mensaje a un cliente en particular" . El código es muy simple de entender. Vamos a verlo.
Servidor
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);
El servidor comienza a escuchar en el puerto 8000 las conexiones entrantes. Cuando uno llega, agrega ese nuevo cliente a un mapa para que pueda hacer un seguimiento de su número de secuencia. También escucha el evento de disconnect
ese cliente, cuando lo eliminará del mapa.
Cada segundo, se dispara un temporizador. Cuando lo hace, el servidor camina por el mapa y envía un mensaje a cada cliente con su número de secuencia actual. Luego lo incrementa y almacena el número en el mapa. Eso es todo lo que es eso. Pan comido.
Cliente
La parte del cliente es incluso más simple. Simplemente se conecta al servidor y escucha el mensaje seq-num
, imprimiéndolo en la consola cada vez que llega.
client.js
const
io = require("socket.io-client"),
ioClient = io.connect("http://localhost:8000");
ioClient.on("seq-num", (msg) => console.info(msg));
Ejecutando el ejemplo
Instale las bibliotecas requeridas:
npm install socket.io
npm install socket.io-client
Ejecute el servidor:
node server
Abra otras ventanas de terminal y engendre tantos clientes como desee ejecutando:
node client
También preparé una esencia con el código completo here .
A partir de la versión 1.4.5, asegúrese de proporcionar un socketId correctamente prefijado en io.to (). ¡Estaba tomando el socketId que el cliente inició la depuración y no tenía prefijo, así que terminé buscando hasta que me enteré! Por lo tanto, puede que tenga que hacerlo así si el ID que tiene no está prefijado:
io.to(''/#'' + socketId).emit(''myevent'', {foo: ''bar''});
Bueno, tienes que agarrar al cliente por eso (sorpresa), puedes ir por el camino simple:
var io = io.listen(server);
io.clients[sessionID].send()
Lo cual puede romperse, casi lo dudo, pero siempre existe la posibilidad de que io.clients
cambie, así que use lo anterior con precaución
O puede hacer un seguimiento de los clientes usted mismo, por lo tanto, los agrega a su objeto de clients
en el oyente de connection
y los elimina en el oyente de disconnect
.
clients[id] = {conn: clientConnect, data: {...}}
este último, ya que dependiendo de su aplicación, es posible que desee tener más estado en el para los clientes de todos modos, así que algo como clients[id] = {conn: clientConnect, data: {...}}
podría hacer trabajo.
Cualquiera que sea la versión que estamos utilizando si solo console.log () el objeto "io" que usamos en nuestro código del nodo del lado del servidor, [por ejemplo, io.on (''connection'', function (socket) {...});] , podemos ver que "io" es solo un objeto json y hay muchos objetos secundarios donde se almacenan los objetos id y socket de socket.
Estoy usando socket.io versión 1.3.5, por cierto.
Si miramos en el objeto io, contiene,
sockets:
{ name: ''/'',
server: [Circular],
sockets: [ [Object], [Object] ],
connected:
{ B5AC9w0sYmOGWe4fAAAA: [Object],
''hWzf97fmU-TIwwzWAAAB'': [Object] },
aquí podemos ver los socketids "B5AC9w0sYmOGWe4fAAAA" etc. Así que, podemos hacer,
io.sockets.connected[socketid].emit();
Nuevamente, en una inspección adicional podemos ver segmentos como,
eio:
{ clients:
{ B5AC9w0sYmOGWe4fAAAA: [Object],
''hWzf97fmU-TIwwzWAAAB'': [Object] },
Entonces, podemos recuperar un socket desde aquí haciendo
io.eio.clients[socketid].emit();
Además, en el motor tenemos,
engine:
{ clients:
{ B5AC9w0sYmOGWe4fAAAA: [Object],
''hWzf97fmU-TIwwzWAAAB'': [Object] },
Entonces, también podemos escribir,
io.engine.clients[socketid].emit();
Entonces, supongo que podemos lograr nuestro objetivo en cualquiera de las 3 formas que enumeré anteriormente,
- io.sockets.connected [socketid] .emit (); O
- io.eio.clients [socketid] .emit (); O
- io.engine.clients [socketid] .emit ();
En 1.0 debes usar:
io.sockets.connected[socketid].emit();
La respuesta de Ivo Wetzel ya no parece válida en Socket.io 0.9.
En resumen, ahora debe guardar el socket.id
y usar io.sockets.socket(savedSocketId).emit(...)
para enviarle mensajes.
Así es como conseguí que esto funcionara en el servidor agrupado de Node.js:
Primero debe configurar la tienda Redis como la tienda para que los mensajes puedan pasar por procesos cruzados:
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);
});
});
});
He omitido el código de clúster aquí, porque lo hace más desordenado, pero es trivial de agregar. Solo agregue todo al código de trabajador. Más documentos aquí http://nodejs.org/api/cluster.html
Puedes hacerlo
En el servidor
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 "});
}
Y en el cliente, es muy fácil de manejar.
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)
})
Puedes usar
// enviar mensaje solo al remitente-cliente
socket.emit(''message'', ''check this'');
// o puede enviarlo a todos los oyentes, incluido el remitente
io.emit(''message'', ''check this'');
// enviar a todos los oyentes, excepto el remitente
socket.broadcast.emit(''message'', ''this is a message'');
// o puede enviarlo a una habitación
socket.broadcast.to(''chatroom'').emit(''message'', ''this is the message to all'');
Socket.IO le permite "espacio de nombres" de sus sockets, lo que esencialmente significa asignar diferentes puntos finales o rutas.
Esto podría ayudar: http://socket.io/docs/rooms-and-namespaces/
cada socket se une a una sala con una identificación de socket para un nombre, por lo que puede simplemente
io.to(socket#id).emit(''hey'')
documentos: http://socket.io/docs/rooms-and-namespaces/#default-room
Aclamaciones
io.sockets.sockets [socket.id] .emit (...) funcionó para mí en v0.9