Как отправить сообщение конкретному клиенту с помощью 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);
}

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

az7ar
источник
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

Лалит Мохан
источник