Отправка сообщения конкретным подключенным пользователям с помощью webSocket?

Я написал код для трансляции сообщения всем пользователям:

Используемый код: (краткий)

// 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 хочет отправить сообщение клиенту конкретному (John).

И вот вопрос:

  • Как сервер NodeJs знает, какое соединение имеет Джон?

    Сервер NodeJs даже не знает Джона. все, что он видит, это соединения.

Итак, Я считаю, что теперь я не должен хранить пользователей только по их соединению, вместо этого мне нужно сохранить объект, который будет содержать объект userId и connection.

И вот моя идея:


  • Когда загрузка страницы заканчивается (Dom ready) - установите соединение с сервером NodeJs.

  • Когда сервер NodeJs принимает соединение - генерирует уникальную строку и отправляет ее в клиентский браузер. Храните пользовательское соединение и уникальную строку в объекте. , например {UserID:"6" , value :{connectionObject}}

  • На стороне клиента, когда приходит это сообщение, сохраните его в скрытом поле или в файле cookie. (для будущих запросов к серверу NodeJs)


Когда сервер хочет отправить сообщение Джону:

  • Найти john UserID в словаре и отправить сообщение по соответствующему соединению.

Обратите внимание, что здесь нет кода сервера asp.net, который находится здесь (в механизме сообщения). только NodeJs.

Вопрос:

Это правильный путь? (или я что-то пропустил?)

Ответ 1

Это не только правильный путь, но единственный способ. В основном для каждого соединения требуется уникальный идентификатор. В противном случае вы не сможете их идентифицировать, это так просто.

Теперь, как вы это представляете, это другое дело. Создание объекта с id и connection свойствами - хороший способ сделать это (я бы определенно пошел на это). Вы также можете привязать id к объекту соединения.

Также помните, что если вы хотите общаться между пользователями, вам также нужно отправить целевой идентификатор пользователя, то есть когда пользователь A хочет отправить сообщение пользователю B, тогда, очевидно, A должен знать идентификатор B.

Ответ 2

Здесь простой чат-сервер приватных/прямых сообщений.

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. Затем, чтобы запустить сервер чата, запустите node server.js (или npm start) на одной вкладке "Терминал". Затем на другой вкладке "Терминал" запустите wscat -c ws://localhost:5000/1, где 1 - это идентификатор пользователя подключающегося пользователя. Затем на третьей вкладке "Терминал" запустите wscat -c ws://localhost:5000/2, а затем, чтобы отправить сообщение от пользователя 2 к 1, введите ["1", "Hello, World!"].

Упущения

Этот чат-сервер очень прост.

  • Упорство

    Он не хранит сообщения в базе данных, такой как PostgreSQL. Таким образом, пользователь, которому вы отправляете сообщение, должен быть подключен к серверу для его получения. В противном случае сообщение будет потеряно.

  • Безопасность

    Это небезопасно.

    • Если я знаю URL-адрес сервера и идентификатор пользователя Алисы, то я могу выдать себя за Алису, то есть подключиться к серверу как она, что позволит мне получать ее новые входящие сообщения и отправлять сообщения от нее любому пользователю, чей идентификатор пользователя я также знаю. Чтобы сделать его более безопасным, измените сервер, чтобы он принимал ваш токен доступа (вместо вашего идентификатора пользователя) при подключении. Затем сервер может получить ваш идентификатор пользователя из вашего токена доступа и аутентифицировать вас.

    • Я не уверен, поддерживает ли он соединение WebSocket Secure (wss://), поскольку я проверял его только на localhost wss:// и не уверен, как безопасно подключиться с localhost.

Ответ 3

Я хотел бы поделиться тем, что я сделал. Надеюсь, это не тратит ваше время.

Я создал таблицу базы данных, содержащую идентификатор поля, IP, имя пользователя, время входа в систему и время выхода. Когда пользователь регистрируется в режиме logintime, будет выполняться коррекция unixtimestamp unix. И когда соединение запущено в базе данных websocket, выполняется проверка для самого большого времени входа в систему. Он войдет в систему.

И когда пользователь выйдет из системы, он сохранит время регистрации. Пользователь станет тем, кто покинул приложение.

Всякий раз, когда появляется новое сообщение, сравниваются идентификатор и IP-адрес Websocket, а также отображается связанное с ним имя пользователя. Ниже приведен пример кода...

// 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
} 

Ответ 4

интересный пост (похоже на то, что я делаю). Мы создаем API (в С#) для соединения диспенсеров с WebSockets, для каждого диспенсера мы создаем ConcurrentDictionary, в котором хранится WebSocket и DispenserId, что упрощает для каждого диспенсера создание WebSocket и его последующее использование без проблем с потоками (вызывая определенные функции на WebSocket, как GetSettings или RequestTicket). Разница для вас в этом примере заключается в использовании ConcurrentDictionary вместо массива для изоляции каждого элемента (никогда не пытался сделать это в javascript). С наилучшими пожеланиями,

Ответ 5

Для людей, использующих ws версии 3 или выше. Если вы хотите использовать ответ, предоставленный @ma11hew28, просто измените этот блок следующим образом.

webSocketServer.on('connection', function (webSocket) {
  var userID = parseInt(webSocket.upgradeReq.url.substr(1), 10)
webSocketServer.on('connection', function (webSocket, req) {
  var userID = parseInt(req.url.substr(1), 10)

Пакет ws переместить upgradeReq для запроса объекта, для получения дополнительной информации вы можете проверить следующую ссылку.

Ссылка: https://github.com/websockets/ws/issues/1114