99

我正在尝试将套接字与 node.js 一起使用,我成功了,但我不知道如何在我的代码中区分客户端。关于套接字的部分是这样的:

var WebSocketServer = require('ws').Server, 
    wss = new WebSocketServer({port: 8080});
wss.on('connection', function(ws) {
    ws.on('message', function(message) {
        console.log('received: %s', message); 
        ws.send(message);
    });
    ws.send('something');
});

此代码适用于我的客户端 js。

但我想向特定用户或在我的服务器上打开套接字的所有用户发送消息。

在我的情况下,我作为客户端发送消息并收到响应,但其他用户什么也没显示。

例如,我想 user1 通过 webSocket 向服务器发送一条消息,然后我向他的套接字打开的 user2 发送一条通知。

4

12 回答 12

119

在nodejs中可以直接修改ws客户端,分别为每个客户端添加自定义属性。此外,您还有一个全局变量wss.clients,可以在任何地方使用。请尝试下一个代码并尝试连接至少两个客户端:

var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({
    server: httpsServer
});


wss.getUniqueID = function () {
    function s4() {
        return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
    }
    return s4() + s4() + '-' + s4();
};

wss.on('connection', function connection(ws, req) {
    ws.id = wss.getUniqueID();

    wss.clients.forEach(function each(client) {
        console.log('Client.ID: ' + client.id);
    });
});

您也可以直接在客户端连接 URL 中传递参数:

https://myhost:8080?myCustomParam=1111&myCustomID=2222

在连接函数中,您可以获取这些参数并将这些参数直接分配给您的 ws 客户端:

wss.on('connection', function connection(ws, req) {

    const parameters = url.parse(req.url, true);

    ws.uid = wss.getUniqueID();
    ws.chatRoom = {uid: parameters.query.myCustomID};
    ws.hereMyCustomParameter = parameters.query.myCustomParam;
}
于 2017-10-22T19:35:19.253 回答
68

您可以简单地将用户 ID 分配给数组 CLIENTS[],这将包含所有用户。您可以直接向所有用户发送消息,如下所示:

var WebSocketServer = require('ws').Server,
    wss = new WebSocketServer({port: 8080}),
    CLIENTS=[];

wss.on('connection', function(ws) {
    CLIENTS.push(ws);
    ws.on('message', function(message) {
        console.log('received: %s', message);
        sendAll(message);
    });
    ws.send("NEW USER JOINED");
});

function sendAll (message) {
    for (var i=0; i<CLIENTS.length; i++) {
        CLIENTS[i].send("Message: " + message);
    }
}
于 2013-06-20T20:56:14.810 回答
13

您可以使用请求标头“sec-websocket-key”

wss.on('connection', (ws, req) => {
  ws.id = req.headers['sec-websocket-key']; 

  //statements...
});
于 2018-05-18T08:56:57.427 回答
11

Worlize 服务器中的这段代码片段对我帮助很大。即使您使用的是 ws,代码也应该很容易适应。我在这里选择了重要的部分:

// initialization
var connections = {};
var connectionIDCounter = 0;

// when handling a new connection
connection.id = connectionIDCounter ++;
connections[connection.id] = connection;
// in your case you would rewrite these 2 lines as
ws.id = connectionIDCounter ++;
connections[ws.id] = ws;

// when a connection is closed
delete connections[connection.id];
// in your case you would rewrite this line as
delete connections[ws.id];

现在您可以轻松地创建一个 broadcast() 和 sendToConnectionId() 函数,如链接代码所示。

希望有帮助。

于 2013-03-06T19:27:39.227 回答
8

这取决于您使用的是哪个 websocket。例如,最快的一个,在这里找到:https ://github.com/websockets/ws能够通过这种方法进行广播:

var WebSocketServer = require('ws').Server,
   wss = new WebSocketServer({host:'xxxx',port:xxxx}),
   users = [];
wss.broadcast = function broadcast(data) {
wss.clients.forEach(function each(client) {
  client.send(data);
 });
};

然后稍后在您的代码中,您可以使用 wss.broadcast(message) 发送给所有人。为了向单个用户发送 PM,我执行以下操作:

(1) 在我发送到服务器的消息中,我包含一个用户名 (2) 然后,在 onMessage 中,我使用该用户名将 websocket 保存在数组中,然后稍后通过用户名检索它:

wss.on('connection', function(ws) {

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

      users[message.userName] = ws;

(3) 要发送给特定用户,您可以执行 users[userName].send(message);

于 2015-10-14T19:16:53.513 回答
4

我正在使用 ws 对象中的 fd 。每个客户端应该是唯一的。

var clientID = ws._socket._handle.fd;

当我打开一个新的浏览器标签时,我得到一个不同的号码。

第一个 ws 有 11 个,下一个有 12 个。

于 2015-07-25T19:05:56.947 回答
3

您可以检查连接对象。它为每个连接的客户端提供内置标识;你可以在这里找到它:

let id=ws._ultron.id;
console.log(id);
于 2017-08-22T11:02:08.470 回答
2

一种可能的解决方案是在用户 ID 前面附加 deviceId,因此我们可以将具有相同用户 ID 但在不同设备上的多个用户分开。

ws://xxxxxxx:9000/userID/<<deviceId>>

于 2017-11-14T12:06:26.300 回答
0

如果您的意思是打开的连接,则客户端可以ws.upgradeReq.headers['sec-websocket-key']用作标识符。并将所有套接字对象保存在一个数组中。

但是如果你想识别你的用户,那么你需要将用户特定的数据添加到套接字对象。

于 2017-04-25T11:27:00.333 回答
0

如果这里有人可能正在使用koa-websocket库,则 WebSocket 的服务器实例将附加到ctx请求旁边。wss.clients这使得操作Set(ws中的会话集)变得非常容易。例如,通过 URL 传递参数并将其添加到 Websocket 实例,如下所示:

const wss = ctx.app.ws.server
const { userId } = ctx.request.query

try{

   ctx.websocket.uid = userId

}catch(err){
    console.log(err)
}
于 2018-11-03T13:07:08.543 回答
0

使用全局计数器变量并为每个新连接分配其值:

const wss = new WebSocket.Server({server});
let count_clients = 0;
wss.on('connection', function connection(ws){
    ws.id=count_clients++;
    console.log(`new connection, ws.id=${ws.id}, ${ws._socket.remoteAddress}:${ws._socket.remotePort} #clients=${wss.clients.size}`);
    ws.on('close', req => {console.log(`disconnected, ws.id=${ws.id}, ${ws._socket.remoteAddress}:${ws._socket.remotePort} #clients=${wss.clients.size}`);});
...
于 2021-08-11T12:02:13.700 回答
0

这是我所做的:

* on connect, server generate an unique id (e.g uuid) for the connection,
    * save it in memory, (e.g as key of map),
    * send back to client in response,
    * 
* 
* client save the id, on each request with also send the id as part of request data,
* then server identify the client by id, on receive further request,
* 
* server maintain client, e.g cleanup on close/error,
* 

我已经实现了这个想法,它可以很好地识别客户。
并且,我还基于这个想法实现了组/主题广播,这需要服务器维护额外的信息。

于 2022-02-03T19:08:41.320 回答