Отправить сообщение конкретному клиенту с помощью socket.io и node.js - PullRequest
173 голосов
/ 10 января 2011

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

client.send(message, receiverSessionId)

Но ни .send(), ни .broadcast() методы, похоже, не удовлетворяют мою потребность.

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

Есть идеи?

Ответы [ 11 ]

169 голосов
/ 22 марта 2012

Ответ Иво Ветцела больше не действителен в 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

91 голосов
/ 10 января 2011

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

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

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

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

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

86 голосов
/ 03 декабря 2014

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

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

документы: http://socket.io/docs/rooms-and-namespaces/#default-room

Приветствия

73 голосов
/ 15 июня 2014

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

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

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

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

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

Клиент

Клиентская часть еще проще. Он просто подключается к серверу и прослушивает сообщение 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

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

33 голосов
/ 30 октября 2014

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

io.sockets.connected[socketid].emit();
29 голосов
/ 25 июня 2016

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

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

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

12 голосов
/ 17 июня 2015

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

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

Если мы посмотрим на объект 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();

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

  1. io.sockets.connected [socketid] .emit (); OR
  2. io.eio.clients [socketid] .emit (); OR
  3. io.engine.clients [socketid] .emit ();
11 голосов
/ 27 июля 2015

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

На сервере.

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)
    })
6 голосов
/ 22 июля 2016

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

io.to('/#' + socketId).emit('myevent', {foo: 'bar'});
4 голосов
/ 01 февраля 2014

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...