简体   繁体   English

Websockets:向除发件人以外的所有客户端发送消息和通知

[英]Websockets: send messages and notifications to all clients except sender

I am developing chat based on websockets and webrtc.我正在开发基于 websockets 和 webrtc 的聊天。 I would like to send messages to all connected users except sender but I cannot find suitable solution.我想向除发件人以外的所有连接用户发送消息,但我找不到合适的解决方案。 To be more specific, I would like to send notifications to other connected users that new user has joined to the chat.更具体地说,我想向其他连接的用户发送新用户已加入聊天的通知。 I am trying to give a unique ID to every connected user, but the first assigned ID is re-writed by every new user and I cannot diferentiate users.我试图为每个连接的用户提供一个唯一的 ID,但是每个新用户都会重写第一个分配的 ID,我无法区分用户。

Server:服务器:

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

Client:客户:

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

I would highly appreciate If you could give me any hint.如果您能给我任何提示,我将不胜感激。 Thanks谢谢

Here is a very simple way of sending to everyone connected except the sender.这是一种非常简单的方法,可以发送给除发件人之外的所有连接的人。

Create a broadcast function on your webSocketServer instance that will take two params.在您的 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);
})

That's it, the broadcast method will send to each connected client except the one who is sending.就是这样,广播方法将发送到每个连接的客户端,除了正在发送的客户端。

Ok, so we are now storing the CLIENTS in a way that allows us to uniquely identify each client that is connecting, and store arbitrary information about them for later retrieval.好的,所以我们现在以一种允许我们唯一标识每个正在连接的客户端的方式存储客户端,并存储有关它们的任意信息以供以后检索。

The code below will send the "notes" message to all clients, and THEN add the newly connecting client to the "all clients" list.下面的代码将向所有客户端发送“notes”消息,然后将新连接的客户端添加到“所有客户端”列表中。

SERVER.JS:服务器.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 (for your reference):我的 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
        }));
    }

});

AND THE CLIENT.HTML TO GO WITH IT:以及与之配套的 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>

Ive tested this with NWJS v0.12.3 running the server and Firefox on the client.我已经用 NWJS v0.12.3 测试过这个,在客户端上运行服务器和 Firefox。

This should work这应该工作

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

    });


});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM