【问题标题】:Websockets: send messages and notifications to all clients except senderWebsockets:向除发件人以外的所有客户端发送消息和通知
【发布时间】:2016-06-02 19:41:18
【问题描述】:

我正在开发基于 websockets 和 webrtc 的聊天。我想向除发件人之外的所有连接用户发送消息,但我找不到合适的解决方案。更具体地说,我想向其他已连接的用户发送新用户已加入聊天的通知。 我试图为每个连接的用户提供一个唯一的 ID,但第一个分配的 ID 被每个新用户重写,我无法区分用户。

服务器:

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

如果您能给我任何提示,我将不胜感激。谢谢

【问题讨论】:

    标签: javascript json node.js websocket webrtc


    【解决方案1】:

    这应该可以工作

    const WebSocket = require('ws');
    
    // Websocket variables
    const wss = new WebSocket.Server({
        port: 3000
    });
    console.log('Websocket active on port 3000...');
    
    
    // New WebSocket Connection
    wss.on('connection', function connection(ws) {
    
        console.log('new connection')
    
        // On Message Received
        ws.on('message', function incoming(message) {
    
            console.log(message)
            
            // Send To Everyone Except Sender
            wss.clients.forEach(function(client) {
                if (client !== ws) client.send(message);
            });
    
        });
    
    
    });
    

    【讨论】:

      【解决方案2】:

      这是一种非常简单的方法,可以发送给除了发件人之外的所有连接的人。

      在您的 webSocketServer 实例上创建一个广播函数,该函数将 取两个参数。

      ...
      var webSocketServer = new WebSocketServer.Server({ port: 8081 });
      ...
      /*
       * method: broadcast
       * @data: the data you wanna send
       * @sender: which client/ws/socket is sending
       */
      webSocketServer.broadcast = function(data, sender) {
        webSocketServer.clients.forEach(function(client) {
          if (client !== sender) {
            client.send(data)
          }
        })
      }
      
      ...
      // On your message callback.
      ws.on('message', function(message) {
       ...
        // Note that we're passing the (ws) here
        webSocketServer.broadcast(message, ws);
      })
      

      就是这样,广播方法将发送到每个连接的客户端 发送者除外。

      【讨论】:

        【解决方案3】:

        好的,所以我们现在存储客户端的方式允许我们唯一标识正在连接的每个客户端,并存储有关它们的任意信息以供以后检索。

        下面的代码会将“notes”消息发送给所有客户端,然后将新连接的客户端添加到“所有客户端”列表中。

        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:

        <!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 对此进行了测试。

        【讨论】:

        • 感谢您的回答,我会尽快查看您的回答
        • 您是否更新了对 CLIENTS 的所有引用,请记住我的更改,现在可以使用语法 CLIENTS[string clientLoginName] 访问它。如果您能像以前一样向我展示更新后的代码和错误的屏幕打印,那将非常有帮助。
        • 我刚刚注意到我在代码中拼写错误。很抱歉,我现在更新它。希望您已经注意到并在您的代码中修复了它:D
        • 当然,不用担心 :) 我只是将代码放在 plunker 中,你可以在这里查看:plnkr.co/edit/iVWuGqUduJbJnzVuzGLC?p=catalogue 文件是 server.js 和 client.js
        • 您有完整的 client.js 代码(即定义套接字等的位)吗?我已经在我的 PC 上设置了这个项目并让服务器运行。只需要一个客户端来连接它,这样我就可以测试了。
        猜你喜欢
        • 2012-04-20
        • 1970-01-01
        • 2019-04-29
        • 1970-01-01
        • 1970-01-01
        • 2022-07-01
        相关资源
        最近更新 更多