如何在Node.js的WebSocket服务器中区分客户端?

116

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

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上能正常运行。

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

在我的情况下,我作为客户端发送一条消息并收到响应,但其他用户则什么都没有看到。

例如,我希望用户1通过WebSocket向服务器发送一条消息,并向其打开套接字的用户2发送通知。


你如何定义哪个连接是“user1”,哪个是“user2”? - lanzz
我不太确定,我想在连接时为用户提供一种socketSession。 - Ajouve
5
一旦您知道连接的用户身份(例如,当您的用户将其用户名作为消息发送时),您可以在字典中存储一个命名引用(例如,connections[username] = ws),然后在其他地方,您可以执行类似于 connections[username].send(message) 的操作。 - lanzz
如果您的需求不是针对单个用户,而是针对一组用户(可能是1组)隔离到“房间”中,您可以使用socket join()broadcast()方法。在这里查看一些讨论:https://dev59.com/nGw15IYBdhLWcg3wFHpZ - meetamit
谢谢,它很好地将我所有的ws注册到了一个数组中 :) - Ajouve
13个回答

0

如果你指的是开放连接,那么可以使用 ws.upgradeReq.headers['sec-websocket-key'] 作为标识符,并将所有 socket 对象保存在数组中。

但如果你想要识别你的用户,则需要向 socket 对象添加特定于用户的数据。


0
如果这里有人正在使用koa-websocket库,那么WebSocket服务器实例将与请求一起附加到ctx。这使得操作wss.clients集合(ws中的会话集合)变得非常容易。例如,通过URL传递参数并将其添加到Websocket实例中,可以像这样进行:
const wss = ctx.app.ws.server
const { userId } = ctx.request.query

try{

   ctx.websocket.uid = userId

}catch(err){
    console.log(err)
}

0

有很多有趣的答案可以完成这项工作,但它们大多数似乎不太干净,也就是说,如果您不介意突变ws对象。我这样做是因为我正在使用TypeScript,而您不能随意向对象添加属性。

import WebSocket from 'ws'

declare module 'ws' {
  interface WebSocket {
    id: any
    key: string
  }
}

id不需要是任何类型,可以是数字或字符串,具体取决于您如何标识连接。我还没有完善系统,但暂时当建立连接时,我只分配一个随机数。

const socketConnection = (socket: WebSocket.WebSocket): void => {
  socket.id = Math.random()
  console.log(socket.id)
  const msg = JSON.stringify({ res: `[open] Welcome to the WebSocket server!` })
  socket.send(msg)
}

这可以在任何时候进行修改,因此一旦我验证连接,我计划在此处分配一个相关的ID,并且如果我想要做更多花哨的事情,甚至可能添加一个关键属性。

这是在文档的模块增强部分中解释的。

TypeScript: 模块增强

您可以通过查看onmessage事件中的多个消息来检查它是否仍然被分配。

const socketMessage = (socket: WebSocket.WebSocket): void => {
  socket.on('message', async (message: WebSocket.RawData) => {
    console.log(socket.id)
    console.log(socket.key)
  })
}

顺便提一下,我在设置套接字的文档中进行了此模块声明。但是修改会在文档之间传播。例如,在我开始原型化的AuthController中,我就是这样使用它的。

export default class AuthController {
  public static connections: DLinkedList = new DLinkedList()

  static async validate(request: { id: string, socket: WebSocket.WebSocket }): Promise<void> {
    console.log('test', request.socket.id)

    this.connections.add(request.socket, request.id)
    request.socket.send(JSON.stringify({ res: true }))
    console.log(this.connections.size())
  }

  static getSocket(id: string): WebSocket.WebSocket {
    return this.connections.getAtKey(id).data
  }

  static removeSocket(socket: WebSocket.WebSocket) {

  }
}

你也可以通过直接修改WebSocket对象原型来在纯JS中实现这一点。这里的一些答案谈到了它。我自己没有做过,但原理是类似的。

如何在typescript中为现有类添加方法?

希望这对你有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接