【问题标题】:Assigning WebSocket and net.Socket with unique id分配具有唯一 id 的 WebSocket 和 net.Socket
【发布时间】:2019-07-29 04:03:13
【问题描述】:

我渴望为 Websockets 和 net.Sockets 分配唯一的标识符,因此当收到消息时,客户端通过附加到套接字的标识符来标识。

以往的研究:

对于 Websocket:

根据thisthis,要求如下:

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
wss.on('connection', (ws) => {
   ws.id = uuid.v4(); // This is the relevant line of code
   ws.on('message', (msg: string) => {
   ...
   }
});

对于 net.Socket:

完全一样 - 根据this,需要以下内容:

var server = net.createServer();

server.on('connection', function(conn) {
    conn.id = uuid.v4(); // This is the relevant line of code
    conn.on('data', function(data) {
    ...
    });
});

问题

编译期间错误“属性'id'不存在于类型'WebSocket'[或相应的'Socket']”This 解释了原因。

可选的解决方案 #1:投射到任意位置

更新 net.Socket 代码为:

var server = net.createServer();

server.on('connection', function(conn) {
    (conn as any).id = uuid.v4();
    conn.on('data', function(data) {
        console.log('Session id:' + (conn as any).id);
    });
});

问题:这对我来说似乎不是一个好习惯。除了现在的预感之外,我没有关于原因的参考资料。

可选解决方案 #2:使用局部变量 [似乎是更好的选择]

更新 net.Socket 代码为:

var server = net.createServer();

server.on('connection', function(conn) {
    const id: string = uuid.v4();
    conn.on('data', function(data) {
        console.log('Session id:' + id);
    });
});

经过一番体验,似乎可以正常使用了。

所以 - 问题:

  1. 在可选解决方案#2中:是否保证 id 变量在此范围内始终可用?换句话说:这个解决方案有效吗?对于 net.Socket 和 Websocket?还是我缺少什么?
  2. 一般情况:是否可以使用其他标识符(可能是 WebSocket 和 net.Socket 中的内置标识符)?

[Typescript 版本: 3.2.4]。

【问题讨论】:

标签: node.js typescript sockets websocket


【解决方案1】:

我不知道已经存在的字段。

如果您可以像在选项 2 中那样将套接字 id 保存在局部变量中,那就是我要做的。 我通常更喜欢避免向对象添加任意字段。但是,有时您希望整个应用程序能够访问额外的数据,并且在这些情况下使用局部变量不会工作。

添加自定义字段

除了对any 使用类型断言外,您还可以在项目中添加一个包含以下内容的文件:

declare module "net" {
    interface Socket {
        id: string;
    }
}

这是对net.Socket 接口的扩充,以添加一个字符串形式的id 字段。 这比类型断言更简洁一些,因为类型断言会让拼写错误通过(例如(conn as any).ids)。我使用了你的代码,删除了类型断言并将上述内容添加到名为 @ 的文件中987654327@ 放在包含您的代码的 .ts 文件旁边。 tsc 不再抱怨这个领域。请注意,您不需要导入此文件或以任何方式引用它。您必须只有一个 tsconfig.json 才能将它与您的其他来源一起拾取。默认情况下,由于.d.ts 扩展名,它将被拾取。

在过去,我使用类型断言和接口扩充来向 DOM 节点添加任意字段,并且效果很好。但是,当我这样做时,我使用了非常单数的字段名称,这意味着与可能想要添加自己的字段的其他库发生冲突的可能性非常低。您的字段名称是 id我担心会与其他决定跟踪套接字并将自己的 id 字段添加到套接字的库发生名称冲突。

使用WeakMap

您可以使用另一种方法。您可以设置一个 WeakMap 将套接字与 id 相关联。这是一个插图。你可以有一个模块socket-map,它只导出一个将套接字映射到字符串的映射:

import * as net from "net";

export const socketMap = new WeakMap<net.Socket, string>();

然后你会在获得套接字时将套接字与 id 一起存储:

import * as net from "net";
import * as uuid from "uuid";
import { socketMap } from "./socket-map";

var server = net.createServer();

server.on('connection', function(conn) {
    const id = uuid.v4();
    socketMap.set(conn, id); // You store the socket into the map.
    conn.on('data', function(data) {
        console.log('Session id:' + (conn as any).id);
    });
});

然后,在另一个模块中,您可以通过以下方式获取 id:

import * as net from "net";
import { socketMap } from "./socket-map";

export function foo(conn: net.Socket) {
  const id = socketMap.get(conn);
}

这里我刚刚将套接字与一个 id 字符串相关联,但是您可以在 WeakMap 的值中具有任何您想要的结构。它可能是一个对象,除了 id 之外还包含大量信息。

使用WeakMap 的原因是,虽然WeakMap 对象的键包含对对象的引用,但就垃圾回收而言,这些引用不计入。因此,如果您的应用程序使用套接字完成并且不再引用它而不是 WeakMap,则 WeakMap 中的引用仍然允许垃圾收集器收集套接字。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-04
    • 1970-01-01
    • 2016-12-07
    • 1970-01-01
    • 2023-02-04
    相关资源
    最近更新 更多