Отправить сообщение конкретному клиенту с помощью socket.io и узел.js
Я работаю с socket.io и узел.JS и до сих пор это кажется довольно хорошим, но я не знаю как отправить сообщение от сервера к конкретному клиенту, что-то вроде этого:
client.send(message, receiverSessionId)
но ни то, ни другое .send()
, ни .broadcast()
методы, кажется, обеспечивают мою потребность.
то, что я нашел в качестве возможного решения, это .broadcast()
метод принимает в качестве второго параметра массив с которым отправляется не отправить сообщение, поэтому я могу передать массив со всеми Которым отправляется подключено в данный момент к серверу, за исключением одного, я хочу отправить сообщение, но я чувствую, что там должно быть лучшее решение.
какие идеи?
11 ответов:
Ну вы должны захватить клиента для этого (сюрприз), вы можете либо пойти простым путем:
var io = io.listen(server); io.clients[sessionID].send()
который может сломаться, я в этом почти не сомневаюсь, но всегда есть вероятность, что
io.clients
может измениться, поэтому используйте выше с осторожностьюили вы сами отслеживаете клиентов, поэтому вы добавляете их в свой собственный
ответ Иво Ветцеля, похоже, не действителен Socket.io 0.9 больше.
короче говоря, теперь вы должны сохранить
socket.id
и использоватьio.sockets.socket(savedSocketId).emit(...)
для отправки сообщений на него.вот как я получил эту работу в кластерном узле.сервер JS:
сначала вам нужно установить Redis store в качестве хранилища, чтобы сообщения могли пересекать процессы:
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
каждый сокет присоединяется к комнате с идентификатором сокета имя, так что вы можете просто
io.to(socket#id).emit('hey')
docs:http://socket.io/docs/rooms-and-namespaces/#default-room
Ура
самое простое, самое элегантное решение
это так же просто, как:
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
я также подготовил суть с полный код здесь.
можно использовать
/ / отправить сообщение только отправителю-клиенту
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');
любая версия, которую мы используем, если мы просто консоль.log () объект" io", который мы используем в нашем коде nodejs на стороне сервера, [например, io.on ('connection', function(socket) {...});], мы видим, что" io " - это просто объект json, и есть много дочерних объектов, где хранятся идентификатор сокета и объекты сокета.
Я использую socket.io версия 1.3.5, кстати.
если мы посмотрим в объект ввода-вывода, он содержит,
sockets: { name: '/', server: [Circular], sockets: [ [Object], [Object] ], connected: { B5AC9w0sYmOGWe4fAAAA: [Object], 'hWzf97fmU-TIwwzWAAAB': [Object] },
здесь мы можем увидеть socketids "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.розетки.подключен[socketid].испускают(); Или
- io.Эйо.клиенты[socketid].испускают(); Или
- io.двигатель.клиенты[socketid].излучать();
Вы можете сделать это
на сервере.
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) })
начиная с версии 1.4.5, убедитесь, что вы предоставили правильно префикс socketId в io.to(). Я брал socketId, который клиент регистрировал для отладки, и он был без префикса, поэтому я закончил поиск навсегда, пока не узнал! Так что вам, возможно, придется сделать это так, если идентификатор у вас нет префикса:
io.to('/#' + socketId).emit('myevent', {foo: 'bar'});
Socket.IO позволяет вам "пространство имен" ваших сокетов, что по существу означает назначение разных конечных точек или путей.
Это может помочь: http://socket.io/docs/rooms-and-namespaces/