web-dev-qa-db-ja.com

webSocketを使用して、特定の接続ユーザーにメッセージを送信しますか?

私はallユーザーにメッセージをブロードキャストするためのコードを書きました:

使用コード:(簡単な説明)

// websocket and http servers
var webSocketServer = require('websocket').server;

...
...
var clients = [ ];

var server = http.createServer(function(request, response) {
    // Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
  ...
});

var wsServer = new webSocketServer({
    // WebSocket server is tied to a HTTP server. 
    httpServer: server
});


    // This callback function is called every time someone
    // tries to connect to the WebSocket server
    wsServer.on('request', function(request) {
    ...
    var connection = request.accept(null, request.Origin); 
    var index = clients.Push(connection) - 1;
    ...

気づいてください:

  • ユーザー参照はありませんが、接続しかありません。
  • すべてのユーザー接続はarrayに保存されます。

目標:NodeJsサーバーがメッセージをspecificクライアント(John)に送信したいとします。

そしてここに質問があります:

  • NodeJsサーバーは、Johnがどの接続を持っているかをどのようにして知るのでしょうか?

    NodeJsサーバーはJohnさえも知りません。表示されるのは接続のみです。

だから、今では、接続だけでユーザーを保存するべきではなく、代わりに、userIdconnectionオブジェクト。

そして、ここに私のアイデアがあります:


  • ページの読み込みが完了したら(Dom ready)-NodeJsサーバーへの接続を確立します。

  • NodeJsサーバーが接続を受け入れる場合-一意の文字列を生成し、クライアントブラウザーに送信します。ユーザー接続と一意の文字列をオブジェクトに保存します。 {UserID:"6" , value :{connectionObject}}

  • クライアント側で、このメッセージが到着したら-隠しフィールドまたはCookieに保存します。 (NodeJsサーバーへの将来のリクエスト用)


サーバーがJohnにメッセージを送信する場合:

  • 辞書でjohnのUserIDを見つけ、対応する接続​​でメッセージを送信します。

(メッセージメカニズム内に)ここに含まれるasp.netサーバーコードがないことに注意してください。 NodeJのみ。

質問:

これは正しい方法ですか? (または私は何かを見逃しましたか?)

64
Royi Namir

これは正しい方法であるだけでなく、唯一の方法です。基本的に、各接続には一意のIDが必要です。それ以外の場合、それらを識別することができません、それはそれと同じくらい簡単です。

さて、それをどのように表現するかは、別のものです。 idおよびconnectionプロパティを使用してオブジェクトを作成することは、それを行うための良い方法です(私は間違いなくそれを選びます)。 idを接続オブジェクトに直接アタッチすることもできます。

また、ユーザー間の通信が必要な場合は、ターゲットユーザーのIDも送信する必要があります。つまり、ユーザーAがユーザーBにメッセージを送信する場合、Aは明らかにBのIDを知っている必要があります。

63
freakish

以下は、シンプルなチャットサーバーのプライベート/ダイレクトメッセージングです。

package.json

{
  "name": "chat-server",
  "version": "0.0.1",
  "description": "WebSocket chat server",
  "dependencies": {
    "ws": "0.4.x"
  }
}

server.js

var webSocketServer = new (require('ws')).Server({port: (process.env.PORT || 5000)}),
    webSockets = {} // userID: webSocket

// CONNECT /:userID
// wscat -c ws://localhost:5000/1
webSocketServer.on('connection', function (webSocket) {
  var userID = parseInt(webSocket.upgradeReq.url.substr(1), 10)
  webSockets[userID] = webSocket
  console.log('connected: ' + userID + ' in ' + Object.getOwnPropertyNames(webSockets))

  // Forward Message
  //
  // Receive               Example
  // [toUserID, text]      [2, "Hello, World!"]
  //
  // Send                  Example
  // [fromUserID, text]    [1, "Hello, World!"]
  webSocket.on('message', function(message) {
    console.log('received from ' + userID + ': ' + message)
    var messageArray = JSON.parse(message)
    var toUserWebSocket = webSockets[messageArray[0]]
    if (toUserWebSocket) {
      console.log('sent to ' + messageArray[0] + ': ' + JSON.stringify(messageArray))
      messageArray[0] = userID
      toUserWebSocket.send(JSON.stringify(messageArray))
    }
  })

  webSocket.on('close', function () {
    delete webSockets[userID]
    console.log('deleted: ' + userID)
  })
})

説明書

テストするには、npm installを実行して ws をインストールします。その後、チャットサーバーを起動するには、1つの[ターミナル]タブでnode server.js(またはnpm start)を実行します。次に、別の[ターミナル]タブで、wscat -c ws://localhost:5000/1を実行します。1は接続ユーザーのユーザーIDです。次に、3番目の[ターミナル]タブでwscat -c ws://localhost:5000/2を実行し、ユーザー2から1にメッセージを送信するには、["1", "Hello, World!"]と入力します。

欠点

このチャットサーバーは非常にシンプルです。

  • 持続性

    PostgreSQLなどのデータベースにはメッセージを保存しません。そのため、メッセージを送信するユーザーは、サーバーに接続してメッセージを受信する必要があります。そうしないと、メッセージは失われます。

  • セキュリティ

    安全ではありません。

    • サーバーのURLとAliceのユーザーIDがわかっている場合は、Aliceになりすますことができます。つまり、Aliceとしてサーバーに接続し、新しい着信メッセージを受信して​​、ユーザーIDを知っているユーザーにメッセージを送信できるようにします。より安全にするには、接続時に(ユーザーIDではなく)アクセストークンを受け入れるようにサーバーを変更します。その後、サーバーはアクセストークンからユーザーIDを取得し、ユーザーを認証できます。

    • localhostでしかテストしていないため、WebSocket Secure(wss://)接続をサポートしているかどうかはわかりません。また、localhostから安全に接続する方法もわかりません。

31
ma11hew28

私がやったことを共有したいと思います。時間を無駄にしないことを願っています。

フィールドID、IP、ユーザー名、ログイン時間、ログアウト時間を保持するデータベーステーブルを作成しました。ユーザーがログインすると、logintimeはunixtimestamp unixになります。また、接続がwebsocketデータベースで開始されると、最大ログイン時間がチェックされます。ユーザーがログインします。

また、ユーザーがログアウトすると、正しいログアウト時間が保存されます。ユーザーは、アプリを離れたユーザーになります。

新しいメッセージがあるたびに、Websocket IDとIPが比較され、関連するユーザー名が表示されます。以下はサンプルコードです...

// when a client connects
function wsOnOpen($clientID) {
      global $Server;
      $ip = long2ip( $Server->wsClients[$clientID][6] );

      require_once('config.php');
      require_once CLASSES . 'class.db.php';
      require_once CLASSES . 'class.log.php';

      $db = new database();
      $loga = new log($db);

      //Getting the last login person time and username
      $conditions = "WHERE which = 'login' ORDER BY id DESC LIMIT 0, 1";
      $logs = $loga->get_logs($conditions);
      foreach($logs as $rows) {

              $destination = $rows["user"];
              $idh = md5("$rows[user]".md5($rows["time"]));

              if ( $clientID > $rows["what"]) {
                      $conditions = "ip = '$ip', clientID = '$clientID'  

                      WHERE logintime = '$rows[time]'";
                      $loga->update_log($conditions);
             }
      }
      ...//rest of the things
} 
1
tashi

興味深い投稿(私がやっていることに似ています)。ディスペンサーをWebSocketに接続するためのAPI(C#)を作成しています。ディスペンサーごとに、WebSocketとDispenserIdを格納するConcurrentDictionaryを作成し、各ディスペンサーがWebSocketを簡単に作成し、スレッドの問題なしで使用できるようにします(特定の関数を呼び出します) GetSettingsやRequestTicketなどのWebSocketで)。あなたの例の違いは、配列の代わりにConcurrentDictionaryを使用して各要素を分離することです(javascriptでそのようなことをしようとしたことはありません)。宜しくお願いします、

0
wolf354