101 votes

Envoyer un message à un utilisateur connecté spécifique en utilisant webSocket ?

J'ai écrit un code pour diffuser un message à tous utilisateurs :

// 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;
...

Veuillez noter :

  • Je n'ai pas de référence utilisateur mais seulement une connexion .
  • Toutes les connexions des utilisateurs sont stockées dans un array .

Objectif : Disons que le serveur Node.js veut envoyer un message à un client spécifique (John). Comment le serveur NodeJs saurait-il quelle connexion possède John ? Le serveur Node.js ne connaît même pas John. Tout ce qu'il voit, ce sont les connexions.

Donc, je crois que maintenant, je ne devrais pas stocker les utilisateurs seulement par leur connexion, au lieu de cela, j'ai besoin de stocker un objet, qui contiendra l'information suivante userId y el connection objet.

Idée :

  • Lorsque le chargement de la page est terminé (DOM prêt) - établir une connexion avec le serveur Node.js.

  • Lorsque le serveur Node.js accepte une connexion - générer une chaîne unique et l'envoyer au navigateur du client. Stockez la connexion de l'utilisateur et la chaîne de caractères unique dans un objet, par ex. {UserID:"6", value: {connectionObject}}

  • Côté client, lorsque ce message arrive, il est stocké dans un champ caché ou un cookie. (pour les futures demandes au serveur NodeJs).


Quand le serveur veut envoyer un message à John :

  • Trouvez l'ID utilisateur de John dans le dictionnaire et envoyez un message par la connexion correspondante.

  • veuillez noter qu'il n'y a pas de code serveur asp.net hébergé ici (dans le mécanisme de message). seulement NodeJs .*

Question :

Est-ce la bonne façon de procéder ?

97voto

freakish Points 20067

Ce n'est pas seulement la bonne façon de faire, mais la seule. En fait, chaque connexion a besoin d'un identifiant unique. Sinon, vous ne serez pas en mesure de les identifier, c'est aussi simple que cela.

Maintenant, comment vous allez le représenter, c'est une autre chose. Faire un objet avec id y connection Les propriétés sont un bon moyen de le faire (je le ferais sans hésiter). Vous pouvez également attacher le id directement à l'objet de connexion.

N'oubliez pas non plus que si vous voulez communiquer entre utilisateurs, vous devez également envoyer l'identifiant de l'utilisateur cible, c'est-à-dire que si l'utilisateur A veut envoyer un message à l'utilisateur B, A doit évidemment connaître l'identifiant de B.

56voto

MattDiPasquale Points 23842

Voici un simple serveur de chat de messagerie privée/directe.

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

Instructions

Pour le tester, exécutez npm install pour installer ws . Ensuite, pour démarrer le serveur de chat, exécutez node server.js (o npm start ) dans un seul onglet du terminal. Ensuite, dans un autre onglet du Terminal, exécutez wscat -c ws://localhost:5000/1 donde 1 est l'ID utilisateur de l'utilisateur qui se connecte. Ensuite, dans un troisième onglet du Terminal, exécutez wscat -c ws://localhost:5000/2 et ensuite, pour envoyer un message de l'utilisateur 2 a 1 Entrez ["1", "Hello, World!"] .

Lacunes

Ce serveur de chat est très simple.

  • Persistance

    Il ne stocke pas les messages dans une base de données, telle que PostgreSQL. Ainsi, l'utilisateur auquel vous envoyez un message doit être connecté au serveur pour le recevoir. Sinon, le message est perdu.

  • Sécurité

    Il n'est pas sûr.

    • Si je connais l'URL du serveur et l'ID utilisateur d'Alice, je peux me faire passer pour Alice, c'est-à-dire me connecter au serveur en tant qu'elle, ce qui me permet de recevoir ses nouveaux messages entrants et d'envoyer ses messages à tout utilisateur dont je connais également l'ID utilisateur. Pour plus de sécurité, modifiez le serveur pour qu'il accepte votre jeton d'accès (au lieu de votre ID utilisateur) lors de la connexion. Le serveur peut alors obtenir votre ID utilisateur à partir de votre jeton d'accès et vous authentifier.

    • Je ne suis pas sûr qu'il supporte un WebSocket Secure ( wss:// ) connexion puisque je l'ai seulement testé sur localhost et je ne sais pas comment me connecter de manière sécurisée à partir de localhost .

15voto

Dylandy Points 81

Pour les personnes utilisant ws version 3 ou supérieure. Si vous souhaitez utiliser la réponse fournie par @ma11hew28 il suffit de modifier ce bloc comme suit.

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 le paquet a déménagé upgradeReq pour demander un objet et vous pouvez consulter le lien suivant pour plus de détails.

Référence : https://github.com/websockets/ws/issues/1114

1voto

tashi Points 249

Je voudrais partager ce que j'ai fait. J'espère que cela ne vous fera pas perdre votre temps.

J'ai créé une table de base de données contenant les champs ID, IP, nom d'utilisateur, logintime et logouttime. Lorsqu'un utilisateur se connecte, le temps de connexion sera le currect unixtimestamp unix. Et quand la connexion est lancée dans le websocket, la base de données vérifie le plus grand logintime. Ce sera le moment où l'utilisateur se connectera.

Et lorsque l'utilisateur se déconnecte, il enregistre l'heure de déconnexion actuelle. L'utilisateur deviendra celui qui a quitté l'application.

Lorsqu'il y a un nouveau message, l'ID et l'IP du Websocket sont comparés et le nom d'utilisateur correspondant est affiché. Voici un exemple de code...

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

0voto

wolf354 Points 41

Post intéressant (similaire à ce que je fais). Nous créons une API (en C#) pour connecter des distributeurs avec des WebSockets, pour chaque distributeur nous créons un ConcurrentDictionary qui stocke le WebSocket et le DispenserId, ce qui permet à chaque distributeur de créer facilement un WebSocket et de l'utiliser ensuite sans problèmes de threads (en invoquant des fonctions spécifiques sur le WebSocket comme GetSettings ou RequestTicket). La différence pour votre exemple est l'utilisation de ConcurrentDictionary au lieu d'un tableau pour isoler chaque élément (je n'ai jamais essayé de faire cela en javascript). Meilleures salutations,

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X