Подтвердить что ты не робот

Беспорядочные сообщения в веб-рассылке (не ждите повторной передачи потерянных пакетов)

Когда сервер отправляет сообщение websocket, и пакет теряется, клиент не будет видеть никаких сообщений, пока сервер не поймет, что пакет потерян, повторно передает его и т.д., и он фактически прибывает на клиент... Как вы можете себе представить, это может привести к излишним большим задержкам в приложениях реального времени.

Я знаю, что это происходит по дизайну, потому что TCP обеспечивает доставку пакетов в правильном порядке.

Но мне интересно, есть ли какие-либо библиотеки, похожие на socket.io, которые работают вокруг этого механизма. Казалось бы, много работы написать что-то подобное с нуля.

Работая вокруг, я имею в виду, например, использование UDP вместо TCP с использованием новых функций WebRTC или даже проще, просто создайте несколько соединений в сети и убедитесь, что последовательные сообщения отправляются по разным соединениям.

Я знаю, что клиент потенциально получит устаревшую информацию таким образом, но он может легко компенсировать, игнорируя их. Вам просто нужно дать каждому сообщению инкрементирующий идентификатор.

Например, оболочка для socket.io была бы приятной. То, что имеет тот же интерфейс, но внутренне создает несколько соединений. Я попытался начать писать класс оболочки для этого, но я действительно не уверен, как правильно передавать события между оболочкой и экземплярами socket.io.

Я имею в виду, если я просто передаю все события, запущенные сокетами, в класс-оболочку и все события, запущенные в классе-оболочке, в один из экземпляров socket.io, тогда каждое событие будет крутиться навсегда.

const EventEmitter = require('events');
const Server = require('socket.io');

class ServerWrapper extends EventEmitter {
    constructor() {
        /* instanciation manual:
            new ServerWrapper(httpServer[, options][, connectionCount])
            new ServerWrapper(port[, options][, connectionCount])
            new ServerWrapper(options[, connectionCount])
            (connectionCount is the number of socket.io instances that will be used)
        */

        let port, srv, opts; // not really necessary
        let connCount = 5; //default
        let args = arguments;
        // The following if statements are used to maintain full compatibility with the original socket.io constructor (https://socket.io/docs/server-api/)
        if (arguments.length === 0)
            return;
        else if (arguments.length === 1)
            opts  = arguments[0];
        else if (arguments.length === 2) {
            if (typeof arguments[0] === 'object' && arguments[1] === 'object') {
                srv = arguments[0];
                opts = arguments[1];
            } else if (typeof arguments[0] === 'number' && arguments[1] === 'object') {
               port = arguments[0];
               opts = arguments[1];
            } else if (typeof arguments[0] === 'object' && arguments[1] === 'number') {
                opts = arguments[0];
                connCount = arguments[1];
                args = arguments.pop();
            }
        } else if (arguments.length === 3) {
            opts = arguments[1];
            connCount = arguments[2];
            if (typeof arguments[0] === 'number')
                port = arguments[0];
            else
                srv = arguments[0];
            args = arguments.pop();
        }

        // Create X socket.io instances and store them in this array
        this._io = [];
        for (let i=0; i<connCount; i++)
            this._io.push(new Server(args));

        // Pass all socket.io events to this wrapper class
        this._io.forEach(io=>{
            io.on("*",this.emit);
        });

        // Pass all events fired on this wrapper class to one of the socket.io instances:
        this.nextConn = 0;
        this.on("*", (event,data) => {
            this._io[this.nextConn].emit(...arguments);
            this.nextConn++;
            if (this.nextConn >= this.connCount)
                this.nextConn = 0;
        });

        let sioProps = ['sockets'];
        sioProps.forEach(prop=>{ // map all socket.io properties from the first instance to 'this[prop]'
            this[prop] = this._io[0][prop];
        });

        let sioMethods = ['seveClient','path','adapter','origins','attach','listen','bind','onconnection','of','close'];
        sioMethods.forEach(fName=>{ // redirect all socket.io function calls to all the socket.io instances
            this[fName] = () => {
                this._io.forEach(io=>{
                    this[fName] = io[fName](...arguments);
                });
            };
        });
    }
}
module.exports = ServerWrapper;
4b9b3361

Ответ 1

Проект socket.io-p2p предоставляет интерфейс socket.io вокруг отличного simple-peer Библиотека WebRTC. Если ваше приложение работает в режиме реального времени и может переносить сообщения, выходящие из строя, то вы можете сделать что-то вроде этого, чтобы отключить гарантию заказа (чтобы предотвратить потерянные/поздние сообщения от задержки более поздних сообщений):

let peerOpts = {channelConfig: {ordered: false}}
let p2psocket = new P2P(socket, peerOpts)

Чтобы помочь в поиске документации, обратите внимание, что значение peerOpts становится выбирает параметр для объекта SimplePeer из простого однорангового узла.

Ответ 2

В настоящее время невозможно запустить произвольные UDP-соединения из вашего браузера через WebRTC. Там действительно хорошая запись здесь.

Однако плагины браузеров, безусловно, могут разговаривать с UDP, поэтому, если это приемлемый путь для перехода вниз, ваше приложение может потребовать использования плагина для этой ситуации.

Есть несколько вариантов готовых решений, здесь, в частности:

netcode.io - это netcode-библиотека для разработчиков игр, которая реализует ту же логику TCP-соединения, что и UDP, но без гарантии доступности.

netcode.io-browser - это плагин для браузера Firefox и Chrome, позволяющий использовать netcode.io без разработки собственного расширения браузера.

Надеюсь, что это поможет.