2016-02-21 58 views
0

我正在開發基於websockets和webrtc的聊天。我想發送消息給所有連接的用戶,但發件人除外,但找不到合適的解決方案。更具體地說,我想向新用戶加入聊天的其他已連接用戶發送通知。 我試圖給每個連接的用戶一個唯一的ID,但第一個分配的ID由每個新用戶重新編寫,我無法區分用戶。Websockets:發送消息和通知給所有客戶,除了發件人

服務器:

// list of users 
var CLIENTS=[]; 
var id; 

// web server is using 8081 port 
var webSocketServer = new WebSocketServer.Server({ port: 8081 }); 

// check if connection is established 
webSocketServer.on('connection', function(ws) { 

id = Math.random(); 
CLIENTS[id] = ws; 
CLIENTS.push(ws); 

ws.on('message', function(message) { 
    console.log('received: %s', message); 
    var received = JSON.parse(message); 

    if(received.type == "login"){ 
     ws.send(message); // send message to itself 

     /* *********************************************************** */ 
     /* *** Here I trying to check if message comes from sender *** */ 

     sendNotes(JSON.stringify({ 
      user: received.name, 
      type: "notes" 
     }), ws, id); 

     /* *********************************************************** */ 
    }else if(received.type == "message"){ 
     sendAll(message); // broadcast messages to everyone including sender 
    } 

}); 

ws.on('close', function() { 
    console.log('user ' + CLIENTS[ws] + ' left chat'); 
    delete CLIENTS[ws]; 
}); 

}); 

function sendNotes(message, ws, id) { 
    console.log('sendNotes : ', id); 
    if (CLIENTS[id] !== ws) { 
     console.log('IF : ', message); 
     for (var i = 0; i < CLIENTS.length; i++) { 
      CLIENTS[i].send(message); 
     } 
    }else{ 
     console.log('ELSE : ', message); 
    } 
} 

    function sendAll(message) { 
     for (var i=0; i < CLIENTS.length; i++) { 
      CLIENTS[i].send(message); // broadcast messages to everyone including sender 
     } 
    } 

客戶:

loginButton.addEventListener("click", function(){ 
    name = usernameInput.value; 

    if(name.length > 0){ 
     socket.send(JSON.stringify({ 
      type: "login", 
      name: name 
     })); 
    } 

}); 

function sendData() { 
    var data = dataChannelSend.value; 
    var userName = document.getElementById('greetingUser').innerHTML; 

    socket.send(JSON.stringify({ 
     username : userName, // fetch user name from browser, after login 
     type : "message", 
     message : data 
    })); 
} 

socket.onmessage = function(message) { 

    var envelope = JSON.parse(message.data); 
    switch(envelope.type) { 
     case "login": 
      onLogin(envelope); 
      break; 
     case "message": 
      showMessage(envelope); 
      break; 
    } 
}; 

我將高度讚賞如果你能給我任何暗示。謝謝

回答

1

好的,所以我們現在存儲客戶端的方式允許我們唯一標識每個正在連接的客戶端,並存儲關於它們的任意信息以備以後檢索。

下面的代碼會將「筆記」消息發送給所有客戶端,然後將新連接的客戶端添加到「所有客戶端」列表中。

SERVER.JS:

var http = require('http'), 
    Static = require('node-static'), 
    WebSocketServer = new require('ws'), 

    // list of users 
    /* 
     We are now storing client data like this: 

     CLIENTS = { 

      uniqueRandomClientID: { 

       socket: {},   // The socket that this client is connected on 
       clientDetails: { // Any details you might wish to store about this client 

        username: "", 
        etc: "etc" 
       } 
      } 
     }; 

     So now to get at the socket for a client, it'll be: CLIENTS[uniqueRandomClientID].socket. 
     Or to show a client's username, it'll be: CLIENTS[uniqueRandomClientID].clientDetails.username. 
     You might want to write a 'getClientByUsername' function that iterates the CLIENTS array and returns the client with that username. 
    */ 
    CLIENTS = {}, 

    // web server is using 8081 port 
    webSocketServer = new WebSocketServer.Server({ port: 8081 }); 

// check if connection is established 
webSocketServer.on('connection', function(ws) { 

    console.log('connection is established'); 

    // Now using a randomly generated ID to reference a client. Probably should be better than Math.random :D 
    var wsID = Math.floor(Math.random() * 1000); 

    ws.on('message', function(message) { 

     console.log('received: %s', message); 
     var received = JSON.parse(message); 

     if(received.type == "login"){ 

      // If a client with this login name doesnt exist already, its a new client 
      if(!CLIENTS[wsID]) { 

       doBroadcast(
        { 
         "newuser": received.name, 
         type: "notes" 
        } 
       ); 

       // Now add this new client to the list 
       CLIENTS[wsID] = { 

        socket: ws, 
        clientDetails: { 

         username: received.name 
        } 
       }; 
      } 
     } else if(received.type == "message") { 

      doBroadcast(message); // broadcast messages to everyone including sender 
     } 
    }); 

    ws.on('close', function(_event) { 

     if(CLIENTS[wsID]) { 

      console.log('user ' + CLIENTS[wsID].clientDetails.username + ' left chat'); 
      delete CLIENTS[wsID]; 
     } 
    }); 

    /* 
    * Added this to 'catch' errors rather than just red dump to console. I've never actually done anything with this myself (I *like* red text in my console), but I know this handler should be here :P 
    */ 
    ws.on('error', function(_error) { 

     console.log("error!"); 
     console.log(_error); 
    }); 

    /* 
    * Send an object to a client 
    * 
    * @param WebSocketClient _to - The client you want to send to (generally an index in the CLIENTS array, i.e CLIENTS["bobsusername123"] 
    * @param Object _message - A stringifyable JSON object. Complex ones can screw things up, but your basic key/value pairs are usually fine to send. 
    */ 
    function doSend(_to, _message) { 

     _to.send(JSON.stringify(_message)); 
    }; 

    // Added broadcast function to replace sendAll 
    // Notice how it JSON stringifies the data before sending 
    /* 
    * Broadcast a message to all clients 
    * 
    * @param Object _message - A stringifyable JSON object. Complex ones can screw things up, but your basic key/value pairs are usually fine to send. 
    */ 
    function doBroadcast(_message) { 

     for(var client in CLIENTS) { 

      if(!CLIENTS.hasOwnProperty(client)) continue; 

      doSend(CLIENTS[client].socket, _message); 
     } 
    }; 
}); 

var fileServer = new Static.Server('.'); 
http.createServer(function (req, res) { 

    fileServer.server(req, res); 

}).listen(8080, function(){ 
    console.log("Server is listening 8080 port."); 
}); 

console.log("Server is running on 8080 and 8081 ports"); 

MY CLIENT.JS(參考):

var loginButton = document.getElementById("loginbutton"), 
    usernameInput = document.getElementById("usernameInput"); 

var SocketClient = function(_uri, _callbacks) { 

    this.uri = _uri; 
    this.callbacks = _callbacks; 
}; 

SocketClient.prototype = { 

    send: function(_message) { 

     this.socket.send(_message); 
    }, 

    connect: function() { 

     try { 

      this.socket = new WebSocket("ws://" + this.uri); 
     } catch(e) { return false; } 

     for(var callback in this.callbacks) { 

      if(!this.callbacks.hasOwnProperty(callback)) continue; 
      this.socket["on" + callback] = this.callbacks[callback]; 
     } 

     return true; 
    } 
}; 

var socketClient = new SocketClient(

    "127.0.0.1:8081", 
    { 
     open: function() { 

      console.log("connected."); 
     }, 
     message: function(_message) { 

      console.log("received data:"); 
      console.log(_message); 
     }, 
     close: function() { 

      console.log("closed."); 
     }, 
     error: function(_error) { 

      console.log("error: "); 
      console.log(_error); 
     } 
    } 
); 

socketClient.connect(); 

loginButton.addEventListener("click", function(){ 

    name = usernameInput.value; 

    if(name.length > 0){ 

     socketClient.send(JSON.stringify({ 
      type: "login", 
      name: name 
     })); 
    } 

}); 

及CLIENT.HTML與IT GO:

<!DOCTYPE html> 
<html> 
    <head> 
     <meta charset="utf-8"/> 
    </head> 
    <body> 
     <input type="text" id="usernameInput"/> 
     <button type="button" id="loginbutton">Login</button> 
     <script src="client.js"></script> 
    </body> 
</html> 

伊夫用NWJS v0.12.3在客戶機上運行服務器和Firefox進行測試。

+0

感謝您的回答,我會盡快檢查您的答案 – johannesMatevosyan

+0

它會拋出無效的非字符串緩衝區塊錯誤 – johannesMatevosyan

+0

您是否更新了所有對CLIENTS的引用,並記住了我的更改,現在使用語法CLIENTS [string clientLoginName]。如果您能像以前一樣向我顯示您的更新代碼和錯誤的屏幕打印,那將會非常有幫助。 – whoshotdk

相關問題