Отправить сообщение конкретному клиенту с socket.io и node.js

Я работаю с socket.io и node.js, и до сих пор это кажется довольно хорошим, но я не знаю, как отправить сообщение с сервера конкретному клиенту, примерно так:

client.send(message, receiverSessionId)

Но ни методы .send(), ни .broadcast(), кажется, не приносят моей потребности.

То, что я нашел в качестве возможного решения, заключается в том, что метод .broadcast() принимает в качестве второго параметра массив SessionIds, к которому не посылает сообщение, поэтому я мог бы передать массив со всеми связанными в этот момент сессионными сессиями сервер, за исключением того, который я хочу отправить, но я считаю, что должно быть лучшее решение.

Любые идеи?

Ответ 1

Что ж, вы должны захватить клиента для этого (сюрприз), вы можете пойти простым путем:

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

Что может сломаться, я сомневаюсь в этом, но всегда есть вероятность того, что io.clients может измениться, поэтому используйте вышеизложенное с осторожностью

Или вы сами отслеживаете клиентов, поэтому добавляете их в свой собственный объект clients в прослушивателе connection и удаляете их в прослушивателе disconnect.

Я бы использовал последний, так как в зависимости от вашего приложения вы, возможно, захотите иметь больше состояний на клиентах, так что что-то вроде clients[id] = {conn: clientConnect, data: {...}} может сделать эту работу.

Ответ 2

Ответ Ivo Wetzel, похоже, больше не действителен в Socket.io 0.9.

Короче, вы должны сохранить socket.id и использовать io.sockets.socket(savedSocketId).emit(...) для отправки ему сообщений.

Вот как я работал в кластерном Node.js сервере:

Сначала вам нужно установить Redis как хранилище, чтобы сообщения могли переходить между процессами:

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

});

Здесь я опущен код кластеризации, потому что он делает это более загроможденным, но его тривиально добавлять. Просто добавьте все в рабочий код. Подробнее здесь http://nodejs.org/api/cluster.html

Ответ 3

каждый сокет соединяет комнату с идентификатором сокета для имени, поэтому вы можете просто

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

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

Приветствия

Ответ 4

Самое простое, самое элегантное решение

Это так же просто, как:

client.emit("your message");

И это все.

Но как? Приведи пример

Что нам всем нужно, так это на самом деле полный пример, и вот что следует. Это протестировано с самой последней версией socket.io(2.0.3), а также с использованием современного Javascript (который мы все должны сейчас использовать).

Пример состоит из двух частей: сервера и клиента. Каждый раз, когда клиент подключается, он начинает получать от сервера периодический порядковый номер. Новая последовательность запускается для каждого нового клиента, поэтому сервер должен отслеживать их индивидуально. Это когда "мне нужно отправить сообщение определенному клиенту" вступает в игру. Код очень прост для понимания. Давай посмотрим.

сервера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 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);

Сервер начинает прослушивать порт 8000 на предмет входящих соединений. Когда он прибывает, он добавляет этого нового клиента на карту, чтобы он мог отслеживать его порядковый номер. Он также прослушивает это клиентское событие disconnect, когда удалит его с карты.

Каждую секунду срабатывает таймер. Когда это происходит, сервер проходит по карте и отправляет каждому клиенту сообщение с его текущим порядковым номером. Затем он увеличивает его и сохраняет номер обратно на карте. Это все, что к нему. Легко peasy.

Клиент

Клиентская часть еще проще. Он просто подключается к серверу и прослушивает сообщение seq-num, распечатывая его на консоли каждый раз, когда оно приходит.

client.js

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

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

Выполнение примера

Установите необходимые библиотеки:

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

Запустите сервер:

node server

Откройте другие окна терминала и создайте столько клиентов, сколько вы хотите, запустив:

node client

Я также подготовил суть с полным кодом здесь.

Ответ 5

В 1.0 вы должны использовать:

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

Ответ 6

Вы можете использовать

//отправлять сообщение только отправителю-клиенту

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

//или вы можете отправить всем слушателям, включая отправителя

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

//отправлять всем слушателям, кроме отправителя

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

//или вы можете отправить его в комнату

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

Ответ 7

Какую версию мы используем, если мы просто console.log() объект "io", который мы используем в нашем узле nodejs на стороне сервера, [например. io.on('connection', function (socket) {...});], мы видим, что "io" - это просто объект json, и существует множество дочерних объектов, в которых хранятся объекты сокета и сокет.

Я использую версию socket.io 1.3.5, btw.

Если мы посмотрим в io-объект, он содержит

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

здесь мы видим сокетсиды "B5AC9w0sYmOGWe4fAAAA" и т.д. Итак, мы можем сделать,

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

Опять же, при дальнейшем осмотре мы можем видеть такие сегменты, как

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

Итак, мы можем получить сокет отсюда, выполнив

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

Кроме того, под движком мы имеем

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

Итак, мы также можем написать

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

Итак, я думаю, мы сможем достичь нашей цели любым из трех способов, перечисленных выше,

  • io.sockets.connected [socketid].emit(); ИЛИ
  • io.eio.clients [socketid].emit(); ИЛИ
  • io.engine.clients [socketid].emit();

Ответ 8

Вы можете сделать это

На сервере.

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

И на клиенте это очень легко обрабатывать.

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

Ответ 9

io.sockets.sockets [socket.id].emit(...) работал у меня в v0.9

Ответ 10

Начиная с версии 1.4.5, убедитесь, что в io.to() вы правильно указываете socketId с префиксом. Я принимал socketId, который клиент регистрировал для отладки, и он был без префикса, поэтому я в конечном итоге искал навсегда, пока не узнал! Таким образом, вам может понадобиться сделать это так, если у вас есть идентификатор, который не имеет префикса:

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

Ответ 11

Socket.IO позволяет вам "пространство имен" ваших сокетов, что по существу означает назначение разных конечных точек или путей.

Это может помочь: http://socket.io/docs/rooms-and-namespaces/