Назначение WebSocket и net.Socket с уникальным идентификатором - PullRequest
4 голосов
/ 07 марта 2019

Я стремлюсь назначать 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) => {
   ...
   }
});

Для нетто. Разъем:

То же самое - согласно это , требуется следующее:

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» соответственно] » во время компиляции. Это объясняет почему.

Дополнительное решение № 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 всегда будет доступна в этой области? Другими словами: действительно ли это решение? для обоих нет.Socket & Websocket? Или мне чего-то не хватает?
  2. В общем : Существуют ли дополнительные идентификаторы (возможно, встроенные идентификаторы в WebSocket и net.Socket), которые можно использовать вместо них?

[ Версия машинописного текста: 3.2.4].

1 Ответ

4 голосов
/ 09 марта 2019

Мне не известно о поле, которое уже существует для этого.

Если вы можете сохранить идентификатор сокета в локальной переменной, как в варианте 2, я бы так и сделал. Обычно я предпочитаю избегать добавления произвольных полей к объектам. Однако иногда вы хотите, чтобы все приложение могло получить доступ к дополнительному фрагменту данных, и в этих случаях с использованием локальной переменной won не работает.

Добавление пользовательского поля

Вместо использования утверждения типа для 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

Есть еще один метод, который вы можете использовать. Вы можете установить WeakMap, который связывает сокет с идентификатором. Вот иллюстрация. У вас может быть модуль socket-map, который просто экспортирует карту, отображающую сокеты в строки:

import * as net from "net";

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

И тогда вы получите сокет с идентификатором, когда получите сокет:

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

Затем позже, в другом модуле, вы можете получить идентификатор с:

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

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

Здесь я только что связал сокет со строкой id, но вы можете иметь любую структуру в значениях WeakMap. Это может быть объект, который содержит целый набор информации помимо идентификатора.

Причина использования WeakMap заключается в том, что, хотя ключи объекта WeakMap содержат ссылки на объекты, эти ссылки не учитывают в том, что касается сбора мусора. Таким образом, если ваше приложение выполнено с сокетом и больше не ссылается на него где-либо, кроме WeakMap, ссылка, присутствующая в WeakMap, все еще позволит сборщику мусора сокет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...