Jak wysłać wiadomość do konkretnego klienta za pomocą socket.io

96

Zaczynam od socket.io + node.js, wiem, jak wysłać wiadomość lokalnie i nadać socket.broadcast.emit() funkcję: - wszyscy podłączeni klienci otrzymują tę samą wiadomość.

Teraz chciałbym wiedzieć, jak wysłać prywatną wiadomość do konkretnego klienta, mam na myśli jedno gniazdo do prywatnej rozmowy między 2 osobami (strumień klient-klient). Dzięki.

Nizar B.
źródło
Przepraszam psiphi75, ale ten link nie odpowiada na moją odpowiedź, nie jest powtórzeniem pytania.
Nizar B.
1
@ psiphi75, to nie jest duplikat
softvar
1
Nie znoszę ludzi takich jak @psiphi. Czy jesteś w ogóle programistą? W jaki sposób pytanie dotyczące HTML5 odnosi się do samodzielnej biblioteki? I bez względu na to, co jest warte, WebSockets NIE są Socket.io. Socket.io to biblioteka, która może używać WebSockets, ale ja dygresję. Jest to również bardziej szczegółowe pytanie dotyczące biblioteki, dotyczące wysyłania danych tylko do konkretnych klientów, a nie samej technologii.
Levi Roberts,
@ bugwheels94 Nie bardzo, ten post pochodzi z 2011 roku i ponieważ nodejs miał mnóstwo zmian w kodzie. ten post jest zdecydowanie ważnym pytaniem / odpowiedzią na ten problem.
Nizar B.

Odpowiedzi:

102

Kiedy użytkownik łączy się, powinien wysłać do serwera wiadomość z nazwą użytkownika, która musi być unikalna, np. E-mail.

Para nazwa użytkownika i gniazdo powinny być przechowywane w obiekcie takim jak ten:

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

Na kliencie wyemituj obiekt do serwera z następującymi danymi:

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

Nasłuchuj wiadomości na serwerze. Po odebraniu wiadomości wyemituj dane do odbiorcy.

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

Na kliencie nasłuchuj emisji z serwera o nazwie „ReceivedMessage”, a odczytując dane, możesz obsłużyć, od kogo pochodzą i jaka wiadomość została wysłana.

Adam
źródło
27
Jeśli korzystasz z tego rozwiązania, musisz zrozumieć: 1. Kiedy użytkownik się rozłączy, musisz wyczyścić obiekt „użytkowników” 2. Nie obsługuje drugiego połączenia - na przykład z innej przeglądarki. Więc jeśli użytkownik łączy się z innej przeglądarki - stare połączenie zostanie nadpisane.
Vladimir Kurijov
1
jak można przechowywać obiekt gniazda w magazynie danych? Zakładam, że to nie działa, jeśli masz więcej niż jeden proces węzłowy.
chovy
@chovy musisz użyć redis. Sprawdź ten github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO
Vladimir Kurijov
11
Proponuję nie korzystać z tego rozwiązania. Skończyło się na tym, że straciłem dużo czasu, próbując pokonać ograniczenia tego podejścia. Zobacz rozwiązanie @ az7ar i to wyjaśnienie, dlaczego jest lepsze .
Daniel Que
@DanielQue +1. O wiele lepiej niż natywna funkcjonalność. Dzięki!
Aaron Lelevier
277

Możesz korzystać z pokoi socket.io. Ze strony klienta wyemituj zdarzenie (w tym przypadku "dołączenie" może być dowolne) z dowolnym unikalnym identyfikatorem (email, id).

Strona klienta:

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

Teraz po stronie serwera użyj tych informacji, aby utworzyć unikalne pomieszczenie dla tego użytkownika

Po stronie serwera:

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

Tak więc teraz każdy użytkownik dołączył do pokoju nazwanego na podstawie adresu e-mail użytkownika. Więc jeśli chcesz wysłać konkretnemu użytkownikowi wiadomość, po prostu musisz

Po stronie serwera:

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

Ostatnią rzeczą do zrobienia po stronie klienta jest odsłuchanie zdarzenia „new_msg”.

Strona klienta:

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

Mam nadzieję, że wpadłeś na pomysł.

az7ar
źródło
3
zmień tę linię io.socket.in ('[email protected] '). emit (' new_msg ', {msg:' hello '}); na przykład io.sockets.in ('[email protected] '). emit (' new_msg ', {msg:' hello '});
silvesterprabu
42
Ta odpowiedź jest znacznie lepsza niż obecnie akceptowana odpowiedź. Oto dlaczego: 1) Nie musisz zarządzać globalną tablicą klientów i czyścić ją. 2) Działa nawet wtedy, gdy użytkownik ma otwartych wiele kart na tej samej stronie. 3) Można go łatwo rozszerzyć do pracy z klastrem węzłów (wieloma procesami) z socket.io-redis.
Daniel Que
2
jak zrobić {email: [email protected]}różne dla wszystkich połączeń, czy wszyscy klienci, którzy przechodzą do aplikacji, nie mają użytkownika, [email protected]jak ustawić go jako użytkownika [email protected]dla drugiego klienta, który się łączy, abym mógł mieć różne pokoje. przepraszam, jeśli to irytujące pytanie.
puste gniazdo jack
2
pokochałem to rozwiązanie, ale uważam, że bezpieczeństwo jest tutaj zagrożone. Co jeśli zmienię e-mail w skrypcie po stronie klienta. Teraz mogę czytać także inne prywatne wiadomości. Co ty mówisz?
Gopinath Shiva
3
to nie musi być e-mail
Podałem
32

PEWNOŚĆ: Po prostu,

Oto, czego potrzebujesz:

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

Za każdym razem, gdy użytkownik dołączył do serwera, zostaną wygenerowane szczegóły gniazda, w tym identyfikator. To identyfikator naprawdę pomaga wysłać wiadomość do określonych osób.

najpierw musimy przechowywać wszystkie socket.ids w tablicy,

var people={};

people[name] =  socket.id;

tutaj nazwa to nazwa odbiorcy. Przykład:

people["ccccc"]=2387423cjhgfwerwer23;

Więc teraz możemy pobrać ten socket.id z nazwą odbiorcy za każdym razem, gdy wysyłamy wiadomość:

w tym celu musimy znać nazwę odbiorcy. Musisz wyemitować nazwę odbiorcy do serwera.

ostatnia rzecz to:

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

Mam nadzieję, że to działa dobrze dla Ciebie.

Powodzenia!!

trojański
źródło
Czy możesz utworzyć kod po stronie klienta i po stronie serwera.? Jestem nowy w programowaniu scoket. [email protected]
Harish Mahajan
@HARISH, zapoznaj się z poniższym linkiem, wyjaśnia, co naprawdę dzieje się po stronie klienta. Mam nadzieję, że to pomoże ci bardziej .. socket.io/get-started/chat
Trojan
2
Ale co, jeśli użytkownik rozmawia jednocześnie z 2 innymi osobami. Czy wiadomość od obu użytkowników nie pojawi się w obu oknach?
Sharan Mohandas
Jeśli jest więcej niż dwóch użytkowników, to nie zadziała
Mohhamad Hasham
za każdym razem, gdy użytkownik łączy się z gniazdem, zmienia się identyfikator gniazda, więc jeśli użytkownik otworzy aplikację na wielu kartach, otrzyma odpowiedź na jedną, którą zapisałeś i wysłałeś do innych połączeń gniazd
Vikas Kandari
8

Możesz odnieść się do pokoi socket.io . Kiedy podałeś gniazdo - możesz dołączyć go do nazwanego pokoju, na przykład „user. # {Userid}”.

Następnie możesz wysłać prywatną wiadomość do dowolnego klienta pod dogodną nazwą, na przykład:

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

W powyższej operacji wysyłamy „new_message” do użytkownika „125”.

dzięki.

Vladimir Kurijov
źródło
Cześć kolego, dziękuję za pierwszą odpowiedź, spróbuję i dam Ci znać, ponieważ nie chcę budować czatu, ale prywatnego komunikatora, takiego jak możesz używać w sieci Facebook.
Nizar B.
Czy ktoś może mi pomóc w tej sprawie, naprawdę utknąłem, chciałbym dodać nazwę użytkownika połączoną z moim gniazdem i pozwolić mojej aplikacji na wysyłanie wiadomości do określonego użytkownika, bez czatu, to Facebook jak komunikator. Dzięki, jeśli wiesz!
Nizar B.,
Najpierw musisz zrozumieć, że ta nazwa użytkownika musi być unikalna dla wszystkich użytkowników. A druga - czy nie zapomniałeś zapisać się na wysyłaną wiadomość po stronie klienta?
Vladimir Kurijov 08.07.13
Problem polega na tym, że tracisz możliwość używania callbacków, ponieważ nie są one dozwolone w transmisjach, co tak naprawdę robisz tutaj, transmisja do jego prywatnego pokoju.
bluehallu
@VladimirKurijov, pan Katcha nie chce korzystać z pokoi i zgadzam się, że to nie jest rozwiązanie jego problemu.
miksiii
4

W projekcie naszej firmy stosujemy podejście „pokoje”, a jego nazwa jest połączeniem identyfikatorów wszystkich użytkowników w rozmowie jako unikalnego identyfikatora (nasza implementacja bardziej przypomina komunikator facebookowy), przykład:

| id | nazwa | 1 | Scott | 2 | Susan

Nazwa „pokoju” będzie brzmiała „1-2” (identyfikatory są uporządkowane rosnąco) i po odłączeniu socket.io automatycznie czyści pomieszczenie

w ten sposób wysyłasz wiadomości tylko do tego pokoju i tylko do użytkowników online (połączonych) (mniej pakietów wysyłanych przez serwer).

Rami
źródło
1

Pozwól, że uproszczę to dzięki pokojom socket.io. zażądaj serwera z unikalnym identyfikatorem, aby dołączyć do serwera. tutaj używamy adresu e-mail jako unikalnego identyfikatora.

Klient Socket.io

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

Gdy użytkownik dołączył do serwera, utwórz pokój dla tego użytkownika

Serwer Socket.io

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

Teraz wszyscy jesteśmy gotowi do przyłączenia się. niech wyemituje coś z serwerowni to, aby użytkownik mógł słuchać.

Serwer Socket.io

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

Sfinalizujmy temat wysłuchaniem messagezdarzenia po stronie klienta

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

Odniesienie z pokoi Socket.io

Lalit Mohan
źródło