Como enviar uma mensagem a um determinado cliente com socket.io

95

Estou começando com socket.io + node.js, sei enviar uma mensagem localmente e transmitir a socket.broadcast.emit()função: - todos os clientes conectados recebem a mesma mensagem.

Agora, gostaria de saber como enviar uma mensagem privada para um determinado cliente, ou seja, um soquete para um bate-papo privado entre 2 pessoas (fluxo cliente-para-cliente). Obrigado.

Nizar B.
fonte
Desculpe psiphi75, mas este link não responde à minha resposta, não é uma pergunta duplicada.
Nizar B.
1
@ psiphi75, não é uma duplicata
softvar
1
Não suporto pessoas como @psiphi. Você é mesmo um desenvolvedor? Como uma pergunta específica do HTML5 se relaciona com uma biblioteca autônoma? E para valer a pena, WebSockets NÃO são Socket.io. Socket.io é uma biblioteca que pode USAR WebSockets, mas estou divagando. Esta também é uma questão mais específica relacionada à biblioteca sobre o envio de dados apenas para clientes específicos, não sobre a tecnologia em si.
Levi Roberts
@ bugwheels94 Não realmente, este post é de 2011 e já que nodejs teve um monte de mudanças em termos de código. esta postagem é definitivamente uma pergunta / resposta válida para este problema.
Nizar B.

Respostas:

101

Quando um usuário se conecta, ele deve enviar uma mensagem ao servidor com um nome de usuário que deve ser único, como um e-mail.

Um par de nome de usuário e soquete deve ser armazenado em um objeto como este:

var users = {
    '[email protected]': [socket object],
    '[email protected]': [socket object],
    '[email protected]': [socket object]
}

No cliente, emita um objeto para o servidor com os seguintes dados:

{
    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]
}

No servidor, ouça as mensagens. Quando uma mensagem for recebida, emita os dados para o receptor.

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

No cliente, escute as emissões do servidor chamado 'receivedMessage' e, lendo os dados, você pode identificar de quem eles vieram e a mensagem que foi enviada.

Adão
fonte
26
Se você usar esta solução, então você deve entender: 1. Quando o usuário se desconecta, você deve limpar o objeto 'usuários' 2. Ele não suporta uma segunda conexão - por exemplo, de outro navegador. Portanto, se o usuário se conectar de outro navegador - a conexão antiga será cancelada.
Vladimir Kurijov
1
como você armazenaria o objeto de soquete em um armazenamento de dados? Presumo que isso não funcione se você tiver mais de um processo de nó.
chovy
@chovy você tem que usar redis. Verifique este github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO
Vladimir Kurijov
11
Eu sugiro não usar essa solução. Acabei perdendo muito tempo tentando superar as limitações dessa abordagem. Veja a solução de @ az7ar e esta explicação para saber por que é melhor .
Daniel Que
@DanielQue +1. Muito melhor usar a funcionalidade nativa. Obrigado!
Aaron Lelevier
273

Você pode usar salas socket.io. Do lado do cliente, emita um evento ("join", neste caso, pode ser qualquer coisa) com qualquer identificador único (e-mail, id).

Lado do cliente:

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

Agora, do lado do servidor, use essas informações para criar uma sala exclusiva para esse usuário

Lado do servidor:

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

Então, agora cada usuário entrou em uma sala com o nome do e-mail do usuário. Então, se você quiser enviar uma mensagem para um usuário específico, você só precisa

Lado do servidor:

io.sockets.in('[email protected]').emit('new_msg', {msg: 'hello'});

A última coisa que resta a fazer no lado do cliente é ouvir o evento "new_msg".

Lado do cliente:

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

Espero que você tenha a idéia.

az7ar
fonte
2
altere esta linha io.socket.in ('usuá[email protected]'). emit ('new_msg', {msg: 'hello'}); como este io.sockets.in ('usuá[email protected]'). emit ('new_msg', {msg: 'hello'});
silvesterprabu
42
Esta resposta é muito melhor do que a resposta aceita atualmente. Aqui está o motivo: 1) Você não precisa gerenciar e limpar a matriz global de clientes. 2) Funciona mesmo se um usuário tiver várias guias abertas na mesma página. 3) Pode ser facilmente estendido para trabalhar com um cluster de nó (vários processos) com socket.io-redis.
Daniel Que
2
como faço para fazer {email: [email protected]}diferente para todas as conexões não [email protected]seriam todos os clientes que vão para o aplicativo ter usuário como eu faria [email protected]para o segundo cliente que se conecta para que eu pudesse ter salas diferentes. desculpe se esta é uma pergunta irritante.
jack blank
2
adorei a solução, mas acredito que a segurança está comprometida aqui. E se eu alterar o e-mail no script do lado do cliente. Agora também consigo ler outras mensagens privadas. O que você está dizendo?
Gopinath Shiva
3
não precisa ser um e-mail
Mencionei
32

CERTO: Simplesmente,

Isto é o que você precisa :

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

sempre que um usuário ingressar no servidor, os detalhes do soquete serão gerados, incluindo o ID. Este é o ID realmente ajuda a enviar uma mensagem para pessoas específicas.

primeiro precisamos armazenar todos os socket.ids no array,

var people={};

people[name] =  socket.id;

aqui name é o nome do receptor. Exemplo:

people["ccccc"]=2387423cjhgfwerwer23;

Então, agora podemos obter esse socket.id com o nome do receptor sempre que estivermos enviando a mensagem:

para isso, precisamos saber o nome do destinatário. Você precisa emitir o nome do receptor para o servidor.

a última coisa é:

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

Espero que funcione bem para você.

Boa sorte!!

Trojan
fonte
Você pode criar um código do lado do cliente e do lado do servidor.? Eu sou novo em programação scoket. [email protected]
Harish Mahajan
@HARISH, consulte o link abaixo, explica o que realmente está acontecendo do lado do cliente ... espero que isso ajude você mais .. socket.io/get-started/chat
Trojan
2
Mas e se o usuário estiver conversando com 2 outras pessoas ao mesmo tempo. A mensagem de ambos os usuários não chegará nas duas janelas?
Sharan Mohandas de
Se houver mais de dois usuários, não funcionará direito
Mohhamad Hasham
cada vez que os usuários conectam as mudanças de ID de soquete, caso o usuário abra seu aplicativo em várias guias, ele obterá resposta para uma que você armazenou e enviou para outras conexões de soquete
Vikas Kandari
8

Você pode se referir a salas socket.io . Quando você apertou o soquete - você pode juntá-lo a uma sala nomeada, por exemplo "user. # {Userid}".

Depois disso, você pode enviar mensagem privada para qualquer cliente por nome conveniente, por exemplo:

io.sockets.in ('user.125'). emit ('new_message', {text: "Hello world"})

Na operação acima, enviamos "nova_mensagem" ao usuário "125".

obrigado.

Vladimir Kurijov
fonte
Olá amigo, obrigado pela sua primeira resposta, vou experimentar e informá-lo sobre isso, porque não quero construir um chat, mas sim um messenger privado como você pode usar na rede do Facebook.
Nizar B.
Alguém pode me ajudar com esse assunto, estou realmente travado, gostaria de adicionar um nome de usuário vinculado ao meu soquete e permitir que meu aplicativo envie uma mensagem para um usuário específico, sem sala de chat, é um Facebook como o messenger. Obrigado se você souber!
Nizar B.
Em primeiro lugar, você deve entender que este nome de usuário deve ser único entre todos os usuários. E o segundo - você não esqueceu de se inscrever para a mensagem emitida do lado do cliente?
Vladimir Kurijov
O problema com isso é que você perde a capacidade de usar callbacks, pois eles não são permitidos em broadcasts, que é o que você realmente está fazendo aqui, um broadcast para a sala privada dele.
bluehallu
@VladimirKurijov, Sr. Katcha não quer usar Rooms e concordo que não é a solução para o problema dele.
miksiii
4

Em um projeto de nossa empresa, estamos usando a abordagem de "salas" e seu nome é uma combinação de IDs de usuário de todos os usuários em uma conversa como um identificador único (nossa implementação é mais parecida com o Facebook Messenger), exemplo:

| id | nome | 1 | Scott | 2 | Susan

O nome da "sala" será "1-2" (os ids são ordenados Asc.) e ao desconectar o soquete.io limpa automaticamente a sala

desta forma, você envia mensagens apenas para aquela sala e apenas para usuários online (conectados) (menos pacotes enviados através do servidor).

Rami
fonte
1

Deixe-me simplificar com as salas socket.io. solicitar um servidor com um identificador exclusivo para ingressar em um servidor. aqui estamos usando um e-mail como identificador único.

Cliente Socket.io

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

Quando o usuário entrar em um servidor, crie uma sala para esse usuário

Server Socket.io

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

Agora estamos prontos com a união. deixe emitir algo da tosala do servidor , para que o usuário possa ouvir.

Server Socket.io

io.to('[email protected]').emit('message', {msg: 'hello world.'});

Vamos finalizar o tópico ouvindo o messageevento para o lado do cliente

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

A referência dos quartos Socket.io

Lalit Mohan
fonte