我希望为Websockets和net.Sockets分配唯一的标识符,因此,当收到消息时,客户端将通过套接字上的标识符进行标识。
先前的研究:
对于Websocket:
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) {
...
});
});
问题
在编译过程中,错误“类型'WebSocket'[或相应地为'Socket']上不存在属性'id'” 。 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);
});
});
经过一些尝试后,它似乎可以正常工作。
所以-问题:
[打字稿版本: 3.2.4]。
答案 0 :(得分:4)
我不知道该字段已经存在。
如果您可以像在选项2中那样将套接字ID保留在局部变量中,那就是我要做的。 我通常希望避免向对象添加任意字段。但是,有时您希望整个应用程序都能够访问其他数据,在这种情况下,请使用局部变量将无法正常工作。
您可以在项目中添加一个包含以下内容的文件,而不是对any
使用类型断言:
declare module "net" {
interface Socket {
id: string;
}
}
这正在扩展net.Socket
接口,以添加一个id
字段,它是一个字符串。 这比类型声明要整洁,因为类型声明可以使拼写错误通过(例如(conn as any).ids
)。我使用了您的代码,删除了类型声明并将其添加到文件中我放在包含您的代码的externals.d.ts
文件旁边的名为.ts
的文件中。 tsc
不再抱怨该领域。请注意,您不需要导入此文件或以任何方式引用它。您只需要有一个tsconfig.json
即可将其与您的其他源代码一起拾取。默认情况下,由于扩展名.d.ts
而被选择。
过去,我使用类型断言和接口增强功能将任意字段添加到DOM节点,并且效果很好。但是,当我这样做时,我使用的字段名称非常单一,这意味着与可能要添加自己的字段的其他库发生冲突的可能性很小。您的字段名称是id
。 我担心与其他库的名称冲突,这些库决定它们要跟踪套接字并向套接字添加自己的id
字段。
WeakMap
您可以使用另一种方法。您可以设置将套接字与ID关联的WeakMap
。这是一个例子。您可能有一个模块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
中存在的引用仍将允许垃圾回收器收集套接字。