Когда сервер отправляет сообщение 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;