socket.ioを使用して特定のクライアントにメッセージを送信する方法


95

私はsocket.io + node.jsから始めています、メッセージをローカルに送信してsocket.broadcast.emit()関数をブロードキャストする方法を知っています:-接続されているすべてのクライアントが同じメッセージを受信します。

今、私は特定のクライアントにプライベートメッセージを送信する方法を知りたいのですが、私は2人の間のプライベートチャット用の1つのソケットを意味します(クライアントからクライアントへのストリーム)。ありがとう。


psiphi75は申し訳ありませんが、このリンクは私の回答に返信しません。重複した質問ではありません。
Nizar B.

1
@ psiphi75、それは複製ではありません
softvar

1
@psiphiのような人には我慢できない。あなたも開発者ですか?HTML5固有の質問は、スタンドアロンライブラリとどのように関連していますか?そして、その価値のために、WebSocketはSocket.ioではありません。Socket.ioはWebSocketを使用できるライブラリですが、私は余談です。これは、テクノロジー自体ではなく、特定のクライアントのみにデータを送信することに関するライブラリーに関するより具体的な質問でもあります。
Levi Roberts


@ bugwheels94実際にはそうではありません。この投稿は2011年のものであり、nodejsにはコードの観点から多くの変更が加えられていました。この投稿は間違いなくこの問題に対する有効な質問/回答です。
Nizar B.

回答:


101

ユーザーが接続するとき、それは電子メールのように一意でなければならないユーザー名でサーバーにメッセージを送るべきです。

ユーザー名とソケットのペアは、次のようなオブジェクトに保存する必要があります。

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)

クライアントでは、「receivedMessage」と呼ばれるサーバーからの送信をリッスンします。データを読み取ることにより、送信者と送信されたメッセージを処理できます。


26
このソリューションを使用する場合は、次のことを理解する必要があります。1.ユーザーが切断した場合は、「ユーザー」オブジェクトをクリーンアップする必要があります。2.別のブラウザーなどからの2番目の接続はサポートされていません。したがって、ユーザーが別のブラウザから接続した場合、古い接続は上書きされます。
Vladimir Kurijov 2013

1
ソケットオブジェクトをデータストアにどのように保存しますか?複数のノードプロセスがある場合、これは機能しないと思います。
chovy

@chovyあなたはredisを使わなければなりません。これを確認してくださいgithub.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO
Vladimir Kurijov

11
このソリューションは使用しないことをお勧めします。私はこのアプローチの限界を克服しようとして多くの時間を無駄にしてしまいました。@ az7arのソリューションとこの説明が優れている理由については、この説明をご覧ください。
Daniel Que

@DanielQue +1。ネイティブ機能を使用するよりも優れています。ありがとう!
アーロンLelevier、2015

273

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

私はあなたがアイデアを得ることを望みます。


2
この行を変更してくださいio.socket.in('user1@example.com ')。emit(' new_msg '、{msg:' hello '}); このようにio.sockets.in('user1@example.com ')。emit(' new_msg '、{msg:' hello '});
silvesterprabu 2014

42
この回答は、現在受け入れられている回答よりもはるかに優れています。その理由は次のとおりです。1)クライアントのグローバル配列を管理およびクリーンアップする必要はありません。2)ユーザーが同じページで複数のタブを開いていても機能します。3)を使用して、ノードクラスター(複数のプロセス)で動作するように簡単に拡張できますsocket.io-redis
Daniel Que

2
どのようにすれば{email: user1@example.com}すべての接続を異なるようにできますか?アプリにアクセスするすべてのクライアントuser1@example.comにユーザーuser2@example.comがいません これが迷惑な質問である場合はごめんなさい。
ジャックブランク、

2
ソリューションは気に入りましたが、ここではセキュリティが侵害されていると思います。クライアント側のスクリプトでメールを変更するとどうなりますか?これで、他のプライベートメッセージも読むことができます。何を言っている?
Gopinath Shiva 2016

3
それは私が任意の一意の識別子言及した電子メールである必要はありません
az7ar

32

承知しました: 単純に、

これはあなたが必要なものです:

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

ユーザーがサーバーに参加するたびに、IDを含むソケットの詳細が生成されます。これは、特定の人にメッセージを送信するのに役立つ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 Mahajan

@HARISHは、下のリンクを参照してくださいが、本当にこれは、より多くのあなたを助けクライアントside..i希望..から起こって何かを説明socket.io/get-started/chat
トロイの木馬

2
しかし、ユーザーが同時に他の2人とチャットしている場合はどうでしょう。両方のユーザーからのメッセージが両方のウィンドウに表示されませんか?
Sharan Mohandas

3人以上のユーザーがいる場合、
正しく機能し

ユーザーがソケットIDの変更を接続するたびに、ユーザーが複数のタブでアプリを開いた場合、保存して他のソケット接続に送信したものに応答します
Vikas Kandari

8

socket.io ルームを参照できます。ソケットをハンドシェイクすると、名前付きの部屋に参加できます(例: "user。#{userid}")。

その後、便利な名前で任意のクライアントにプライベートメッセージを送信できます。次に例を示します。

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

上記の操作では、「new_message」をユーザー「125」に送信します。

ありがとう。


こんにちは、最初の答えをありがとう、私はそれを試してそれについてあなたに知らせます。私はチャットを構築したくないが、Facebookネットワークで使用できるようなプライベートメッセンジャーだからです。
Nizar B.

誰かがこの問題を助けてくれますか?私は本当に行き詰まっています。ソケットにリンクされたユーザー名を追加して、アプリケーションが特定のユーザーにメッセージを送信できるようにしたいと思います。チャットルームではなく、メッセンジャーのようなFacebookです。ご存知でしたらありがとうございます!
Nizar B.

最初に、このユーザー名はすべてのユーザー間で一意でなければならないことを理解する必要があります。そして2つ目-クライアント側で発行されたメッセージをサブスクライブすることを忘れませんでしたか?
Vladimir Kurijov 2013

これの問題は、コールバックがブロードキャストで許可されていないため、コールバックを使用する機能を失うことです。これは、ここで実際に行っていることですが、彼のプライベートルームへのブロードキャストです。
bluehallu

@ VladimirKurijov、Katcha氏はRoomsを使用したくないので、彼の問題の解決策ではないことに同意します。
miksiii 2015

4

当社のプロジェクトでは「部屋」アプローチを使用しており、その名前は会話内のすべてのユーザーのユーザーIDを一意の識別子として組み合わせたものです(実装はFacebookのメッセンジャーに似ています)。例:

| id | 名前| 1 | スコット| 2 | スーザン

"部屋"の名前は "1-2"(IDはAsc。で注文されます)になり、切断時に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ルームからの参照

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.