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


96

Я начинаю с socket.io + node.js, я знаю, как отправить сообщение локально и использовать socket.broadcast.emit()функцию широковещания : - все подключенные клиенты получают одно и то же сообщение.

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


Извините, psiphi75, но эта ссылка не отвечает на мой ответ, это не повторяющийся вопрос.
— Низар Б.

1
@ psiphi75, это ни в коем случае не дубликат
— softvar

1
Терпеть не могу таких людей, как @psiphi. Вы вообще разработчик? Как конкретный вопрос HTML5 соотносится с отдельной библиотекой? И как бы то ни было, WebSockets НЕ Socket.io. Socket.io - это библиотека, которая может ИСПОЛЬЗОВАТЬ WebSockets, но я отвлекся. Это также более конкретный вопрос, касающийся библиотеки об отправке данных только определенным клиентам, а не самой технологии.
— Леви Робертс


@ bugwheels94 Не совсем, это сообщение 2011 года, и поскольку в коде nodejs было много изменений. этот пост определенно является правильным вопросом / ответом на эту проблему.
— Низар Б.

Ответы:


102

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

Пара имени пользователя и сокета должна храниться в таком объекте:

var users = {
    'userA@example.com': [socket object],
    'userB@example.com': [socket object],
    'userC@example.com': [socket object]
}

На клиенте отправьте объект на сервер со следующими данными:

{
    to:[the other receiver's username as a string],
    from:[the person who sent the message as string],
    message:[the message to be sent as string]
}

На сервере слушайте сообщения. Когда сообщение получено, отправьте данные получателю.

users[data.to].emit('receivedMessage', data)

На клиенте прислушивайтесь к исходящим сообщениям с сервера, называемого «ReceiveMessage», и, читая данные, вы можете определить, от кого они пришли и какое сообщение было отправлено.


27
Если вы используете это решение, вы должны понимать: 1. Когда пользователь отключается, вы должны очистить объект «пользователи». 2. Он не поддерживает второе соединение - например, из другого браузера. Поэтому, если пользователь подключается из другого браузера, старое подключение будет отменено.
— Владимир Куризов 05

1
как бы вы сохранили объект сокета в хранилище данных? Я предполагаю, что это не сработает, если у вас более одного процесса узла.
— chovy

@chovy, вы должны использовать Redis. Проверьте это github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO
— Владимир Куризов

11
Я предлагаю не использовать это решение. В итоге я потратил много времени, пытаясь преодолеть ограничения этого подхода. См. Решение @az7ar и это объяснение, почему оно лучше .
— Даниэль Ку

@DanielQue +1. Лучше использовать встроенную функциональность. Спасибо!
— Аарон Лелевье,

278

Вы можете использовать комнаты socket.io. Со стороны клиента отправьте событие («присоединиться» в данном случае может быть что угодно) с любым уникальным идентификатором (адрес электронной почты, id).

Сторона клиента:

var socket = io.connect('http://localhost');
socket.emit('join', {email: user1@example.com});

Теперь со стороны сервера используйте эту информацию, чтобы создать уникальную комнату для этого пользователя.

На стороне сервера:

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.on('join', function (data) {
    socket.join(data.email); // We are using room of socket io
  });
});

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

На стороне сервера:

io.sockets.in('user1@example.com').emit('new_msg', {msg: 'hello'});

Последнее, что осталось сделать на стороне клиента, - это прослушать событие "new_msg".

Сторона клиента:

socket.on("new_msg", function(data) {
    alert(data.msg);
}

Надеюсь, вы уловили идею.


3
пожалуйста, измените эту строку io.socket.in ('user1@example.com '). emit (' new_msg ', {msg:' hello '}); как этот io.sockets.in ('user1@example.com '). emit (' new_msg ', {msg:' hello '});
— silvesterprabu

43
Этот ответ намного лучше, чем принятый в настоящее время ответ. Вот почему: 1) Вам не нужно управлять глобальным массивом клиентов и очищать его. 2) Он работает, даже если у пользователя открыто несколько вкладок на одной странице. 3) Его можно легко расширить для работы с кластером узлов (несколько процессов) с socket.io-redis.
— Daniel Que

2
Как сделать {email: user1@example.com}разные соединения для всех подключений? Разве у всех клиентов, которые переходят в приложение, есть пользователь, user1@example.comкак бы мне сделать его пользователем user2@example.comдля второго подключающегося клиента, чтобы у меня были разные комнаты. извините, если это надоедливый вопрос.
— jack blank

2
понравилось решение, но я считаю, что безопасность здесь поставлена ​​под угрозу. Что, если я изменю адрес электронной почты в скрипте на стороне клиента. Теперь я могу читать и другие личные сообщения. Что вы говорите?
— Гопинатх Шива

3
это не обязательно должен быть адрес электронной почты. Я упомянул какой-либо уникальный идентификатор
— az7ar 06

32

УВЕРЕН: просто,

Это то, что вам нужно :

io.to(socket.id).emit("event", data);

всякий раз, когда пользователь присоединяется к серверу, детали сокета будут генерироваться, включая ID. Этот идентификатор действительно помогает отправить сообщение определенным людям.

сначала нам нужно сохранить все socket.ids в массиве,

var people={};

people[name] =  socket.id;

здесь name - имя получателя. Пример:

people["ccccc"]=2387423cjhgfwerwer23;

Итак, теперь мы можем получить этот socket.id с именем получателя всякий раз, когда мы отправляем сообщение:

для этого нам нужно знать имя получателя. Вам необходимо передать на сервер имя получателя.

последнее:

 socket.on('chat message', function(data){
io.to(people[data.receiver]).emit('chat message', data.msg);
});

Надеюсь, это сработает для вас.

Удачи!!


Можете ли вы создать код на стороне клиента и на стороне сервера? Я новичок в программировании scoket. hmahajan.dmi@gmail.com
— Хариш Махаджан

@HARISH, см. Ссылку ниже, объясняет, что на самом деле происходит на стороне клиента ... Надеюсь, это поможет вам больше ... socket.io/get-started/chat
— Trojan

2
Но что, если пользователь общается с двумя другими одновременно. Разве сообщение от обоих пользователей не появится в обоих окнах?
— Шаран Мохандас

Если будет больше двух пользователей, это не сработает,
— Мохамад Хашам,

Каждый раз, когда пользователи подключаются к сокету, изменяется идентификатор, поэтому, если пользователь откроет ваше приложение на нескольких вкладках, он получит ответ на тот, который вы сохранили и отправили другим соединениям сокетов
— Викас Кандари,

8

Вы можете обратиться к комнатам socket.io . Когда вы установили соединение с сокетом - вы можете присоединиться к нему в названной комнате, например "user. # {Userid}".

После этого вы можете отправить личное сообщение любому клиенту по удобному имени, например:

io.sockets.in ('user.125'). emit ('new_message', {текст: "Привет, мир"})

В операции выше мы отправляем «new_message» пользователю «125».

Спасибо.


Привет, приятель, спасибо за ваш первый ответ, я попробую и дам вам знать об этом, потому что я хочу создавать не чат, а частный мессенджер, который вы можете использовать в сети Facebook.
— Низар Б.

Может ли кто-нибудь помочь мне в этом вопросе, я действительно застрял, я хотел бы добавить имя пользователя, связанное с моим сокетом, и разрешить моему приложению отправлять сообщение конкретному пользователю, без чата, это Facebook, как мессенджер. Спасибо, если знаете!
— Низар Б.

Сначала вы должны понять, что это имя пользователя должно быть уникальным для всех пользователей. И второй - не забыли ли вы подписаться на отправленное сообщение на стороне клиента?
— Владимир Куризов 08

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

@VladimirKurijov, господин Катча не хочет использовать комнаты, и я согласен, что это не решение его проблемы.
— miksiii

4

В проекте нашей компании мы используем подход «комнат», и его имя представляет собой комбинацию идентификаторов пользователей всех пользователей в разговоре в качестве уникального идентификатора (наша реализация больше похожа на мессенджер facebook), например:

| id | имя | 1 | Скотт | 2 | Сьюзен

Имя "room" будет "1-2" (идентификаторы упорядочены по возрастанию) и при отключении socket.io автоматически очищает комнату

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


1

Позвольте мне сделать это проще с помощью комнат socket.io. запросить сервер с уникальным идентификатором для присоединения к серверу. здесь мы используем электронную почту в качестве уникального идентификатора.

Клиент Socket.io

socket.on('connect', function () {
  socket.emit('join', {email: user@example.com});
});

Когда пользователь присоединился к серверу, создайте для этого пользователя комнату

Сервер Socket.io

io.on('connection', function (socket) {
   socket.on('join', function (data) {    
    socket.join(data.email);
  });
});

Теперь мы готовы к присоединению. позвольте передать что-то из серверной to, чтобы пользователь мог слушать.

Сервер Socket.io

io.to('user@example.com').emit('message', {msg: 'hello world.'});

Давайте доработаем тему прослушиванием messageсобытия на стороне клиента

socket.on("message", function(data) {
  alert(data.msg);
});

Ссылка из Socket.io rooms

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.