web-dev-qa-db-ja.com

socket.ioおよびnode.jsを使用して特定のクライアントにメッセージを送信します

私はsocket.ioとnode.jsを使っていますが、今まではかなり良いようですが、サーバーから特定のクライアントにメッセージを送信する方法がわかりません:

client.send(message, receiverSessionId)

しかし、.send()メソッドも.broadcast()メソッドも、私のニーズを満たしているようには見えません。

可能な解決策として見つけたのは、.broadcast()メソッドがメッセージを送信しないSessionIdの配列を2番目のパラメーターとして受け入れるため、その瞬間に接続されたすべてのSessionIdを含む配列をサーバーに渡すことができることですメッセージを送信したいのですが、もっと良い解決策があるに違いないと感じています。

何か案は?

173
Rodolfo Palma

さて、あなたはそのためにクライアントをつかまなければなりません(驚き)、あなたは簡単な方法で行くことができます:

var io = io.listen(server);
io.clients[sessionID].send()

これは壊れるかもしれませんが、私はそれを疑うことはほとんどありませんが、io.clientsが変更される可能性は常にあるので、注意して上記を使用してください

または、クライアントを自分で追跡するため、clientsリスナー内の独自のconnectionオブジェクトにクライアントを追加し、disconnectリスナーでそれらを削除します。

アプリケーションに応じてクライアントの状態をもっと維持したい場合があるため、後者を使用します。したがって、clients[id] = {conn: clientConnect, data: {...}}のようなものが仕事をするかもしれません。

91
Ivo Wetzel

Ivo Wetzelの答えはSocket.io 0.9ではもはや有効ではないようです。

つまり、ここでsocket.idを保存し、io.sockets.socket(savedSocketId).emit(...)を使用してメッセージを送信する必要があります。

これは、クラスター化されたNode.jsサーバーでこれを機能させる方法です:

まず、メッセージをプロセス間で移動できるように、Redisストアをストアとして設定する必要があります。

var express = require("express");
var redis = require("redis");
var sio = require("socket.io");

var client = redis.createClient()
var app = express.createServer();
var io = sio.listen(app);

io.set("store", new sio.RedisStore);


// In this example we have one master client socket 
// that receives messages from others.

io.sockets.on('connection', function(socket) {

  // Promote this socket as master
  socket.on("I'm the master", function() {

    // Save the socket id to Redis so that all processes can access it.
    client.set("mastersocket", socket.id, function(err) {
      if (err) throw err;
      console.log("Master socket is now" + socket.id);
    });
  });

  socket.on("message to master", function(msg) {

    // Fetch the socket id from Redis
    client.get("mastersocket", function(err, socketId) {
      if (err) throw err;
      io.sockets.socket(socketId).emit(msg);
    });
  });

});

ここではクラスタリングコードを省略しました。これにより、これが混乱しやすくなりましたが、追加するのは簡単です。ワーカーコードにすべてを追加するだけです。その他のドキュメントはこちら http://nodejs.org/api/cluster.html

169
Epeli

各ソケットは名前のソケットIDでルームに参加するので、

io.to(socket#id).emit('hey')

docs: http://socket.io/docs/rooms-and-namespaces/#default-room

乾杯

85
Matic Kogovšek

最もシンプルでエレガントなソリューション

次のように簡単です:

client.emit("your message");

以上です。

しかし、どのように?例を挙げてください

私たち全員が実際に必要とするのは完全な例であり、それが後に続くものです。これは、最新のsocket.ioバージョン(2.0.3)でテストされており、最新のJavascriptも使用しています(これまでに使用する必要があります)。

この例は、サーバーとクライアントの2つの部分で構成されています。クライアントが接続するたびに、サーバーから定期的なシーケンス番号の受信を開始します。新しいクライアントごとに新しいシーケンスが開始されるため、サーバーはそれらを個別に追跡する必要があります。そこで、「特定のクライアントにメッセージを送信する必要があります」が登場します。コードは非常に簡単に理解できます。それを見てみましょう。

サーバ

server.js

const
    io = require("socket.io"),
    server = io.listen(8000);

let
    sequenceNumberByClient = new Map();

// event fired every time a new client connects:
server.on("connection", (socket) => {
    console.info(`Client connected [id=${socket.id}]`);
    // initialize this client's sequence number
    sequenceNumberByClient.set(socket, 1);

    // when socket disconnects, remove it from the list:
    socket.on("disconnect", () => {
        sequenceNumberByClient.delete(socket);
        console.info(`Client gone [id=${socket.id}]`);
    });
});

// sends each client its current sequence number
setInterval(() => {
    for (const [client, sequenceNumber] of sequenceNumberByClient.entries()) {
        client.emit("seq-num", sequenceNumber);
        sequenceNumberByClient.set(client, sequenceNumber + 1);
    }
}, 1000);

サーバーは、ポート8000​​で着信接続を待機し始めます。到着すると、その新しいクライアントをマップに追加して、シーケンス番号を追跡できるようにします。また、マップから削除するときに、そのクライアントのdisconnectイベントをリッスンします。

毎秒、タイマーが起動されます。それが行われると、サーバーはマップをウォークスルーし、現在のシーケンス番号とともにすべてのクライアントにメッセージを送信します。次に、それをインクリメントし、マップに数値を保存します。それだけです。簡単です。

クライアント

クライアント部分はさらに単純です。サーバーに接続してseq-numメッセージをリッスンし、到着するたびにコンソールに出力します。

client.js

const
    io = require("socket.io-client"),
    ioClient = io.connect("http://localhost:8000");

ioClient.on("seq-num", (msg) => console.info(msg));

サンプルを実行する

必要なライブラリをインストールします。

npm install socket.io
npm install socket.io-client

サーバーを実行します。

node server

次のコマンドを実行して、他のターミナルウィンドウを開き、必要なだけクライアントを生成します。

node client

私も完全なコードで要点を準備しました ここ

73
Lucio Paiva

1.0では、次を使用する必要があります。

io.sockets.connected[socketid].emit();
33
PHPthinking

使用できます

//メッセージを送信者クライアントにのみ送信します

socket.emit('message', 'check this');

//または、送信者を含むすべてのリスナーに送信できます

io.emit('message', 'check this');

//送信者を除くすべてのリスナーに送信します

socket.broadcast.emit('message', 'this is a message');

//または、部屋に送信できます

socket.broadcast.to('chatroom').emit('message', 'this is the message to all');

28
DecoderNT

サーバー側のnodejsコードで使用する「io」オブジェクトをconsole.log()だけで使用する場合は、どのバージョンを使用しますか(例: io.on( 'connection'、function(socket){...});]、「io」は単なるjsonオブジェクトであり、ソケットIDとソケットオブジェクトが格納されている子オブジェクトがたくさんあることがわかります。

私はsocket.ioバージョン1.3.5を使用しています。

Ioオブジェクトを見ると、

 sockets:
  { name: '/',
    server: [Circular],
    sockets: [ [Object], [Object] ],
    connected:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },

ここでsocketids "B5AC9w0sYmOGWe4fAAAA"などを見ることができます。

io.sockets.connected[socketid].emit();

繰り返しますが、さらに詳しく調べると、次のようなセグメントが表示されます。

 eio:
  { clients:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },

そのため、ここからソケットを取得できます

io.eio.clients[socketid].emit();

また、エンジンの下には、

engine:
 { clients:
    { B5AC9w0sYmOGWe4fAAAA: [Object],
      'hWzf97fmU-TIwwzWAAAB': [Object] },

だから、書くこともできます、

io.engine.clients[socketid].emit();

したがって、上記の3つの方法のいずれかで目標を達成できると思います。

  1. io.sockets.connected [socketid] .emit();または
  2. io.eio.clients [socketid] .emit();または
  3. io.engine.clients [socketid] .emit();
12
Suman Barick

あなたはこれを行うことができます

サーバー上。

global.io=require("socket.io")(server);

io.on("connection",function(client){
    console.log("client is ",client.id);
    //This is handle by current connected client 
    client.emit('messages',{hello:'world'})
    //This is handle by every client
    io.sockets.emit("data",{data:"This is handle by every client"})
    app1.saveSession(client.id)

    client.on("disconnect",function(){
        app1.deleteSession(client.id)
        console.log("client disconnected",client.id);
    })

})

    //And this is handle by particular client 
    var socketId=req.query.id
    if(io.sockets.connected[socketId]!=null) {
        io.sockets.connected[socketId].emit('particular User', {data: "Event response by particular user "});
    }

また、クライアントでは、処理が非常に簡単です。

var socket=io.connect("http://localhost:8080/")
    socket.on("messages",function(data){
        console.log("message is ",data);
        //alert(data)
    })
    socket.on("data",function(data){
        console.log("data is ",data);
        //alert(data)
    })

    socket.on("particular User",function(data){
        console.log("data from server ",data);
        //alert(data)
    })
11
abhaygarg12493

バージョン1.4.5の時点で、io.to()で適切にプレフィックスされたsocketIdを提供していることを確認してください。私はクライアントがデバッグするためにログに記録したsocketIdを使用していましたが、プレフィックスがなかったため、最終的に検索することになりました!したがって、所有しているIDに接頭辞が付いていない場合は、次のようにする必要があります。

io.to('/#' + socketId).emit('myevent', {foo: 'bar'});
6
risuch

io.sockets.sockets [socket.id] .emit(...)はv0.9で機能しました

4
aljosa

Socket.IOでは、ソケットを「名前空間」にすることができます。これは、本質的には、異なるエンドポイントまたはパスを割り当てることを意味します。

これは役立つかもしれません: http://socket.io/docs/rooms-and-namespaces/

0
Igor T.