Javascript 无序websocket消息(不要等待丢失数据包的重新传输)

Javascript 无序websocket消息(不要等待丢失数据包的重新传输),javascript,tcp,websocket,socket.io,webrtc,Javascript,Tcp,Websocket,Socket.io,Webrtc,当服务器发送websocket消息且数据包丢失时,客户端将不会看到任何消息,直到服务器意识到数据包丢失、重新传输数据包等,并且数据包实际到达客户端。。。 可以想象,这可能会导致实时应用程序出现不必要的大滞后 我知道这是设计上的,因为TCP确保数据包以正确的顺序传递 但我想知道是否有类似socket.io的库可以围绕这种机制工作。从零开始写这样的东西似乎需要很多工作 所谓变通,我指的是使用UDP而不是TCP,使用新的WebRTC功能或更简单的功能,只需创建多个websocket连接,并确保通过不同

当服务器发送websocket消息且数据包丢失时,客户端将不会看到任何消息,直到服务器意识到数据包丢失、重新传输数据包等,并且数据包实际到达客户端。。。 可以想象,这可能会导致实时应用程序出现不必要的大滞后

我知道这是设计上的,因为TCP确保数据包以正确的顺序传递

但我想知道是否有类似socket.io的库可以围绕这种机制工作。从零开始写这样的东西似乎需要很多工作

所谓变通,我指的是使用UDP而不是TCP,使用新的WebRTC功能或更简单的功能,只需创建多个websocket连接,并确保通过不同的连接发送连续消息

我知道客户可能会以这种方式收到过时的信息,但它可以通过忽略这些信息来轻松地进行补偿。你只需要给每条消息一个递增的id

例如,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;
const EventEmitter=require('events');
const Server=require('socket.io');
类ServerWrapper扩展了EventEmitter{
构造函数(){
/*实例手册:
新的ServerWrapper(httpServer[,选项][,connectionCount])
新服务器包装器(端口[,选项][,连接帐户])
新服务器包装器(选项[,connectionCount])
(connectionCount是将使用的socket.io实例数)
*/
let port,srv,opts;//实际上不需要
让connCount=5;//默认值
设args=参数;
//以下if语句用于保持与原始socket.io构造函数的完全兼容性(https://socket.io/docs/server-api/)
if(arguments.length==0)
返回;
else if(arguments.length==1)
opts=参数[0];
else if(arguments.length==2){
if(参数类型[0]=='object'&&arguments[1]=='object'){
srv=参数[0];
opts=参数[1];
}else if(参数类型[0]=='number'&&arguments[1]=='object'){
端口=参数[0];
opts=参数[1];
}else if(参数类型[0]=='object'&&arguments[1]=='number'){
opts=参数[0];
connCount=参数[1];
args=arguments.pop();
}
}else if(arguments.length==3){
opts=参数[1];
connCount=参数[2];
if(参数类型[0]='number')
端口=参数[0];
其他的
srv=参数[0];
args=arguments.pop();
}
//创建X socket.io实例并将其存储在此阵列中
这个;
for(设i=0;i{
io.on(“*”,this.emit);
});
//将在此包装类上激发的所有事件传递给socket.io实例之一:
this.nextConn=0;
this.on(“*”,(事件、数据)=>{
this.\u io[this.nextConn].emit(…参数);
这个.nextConn++;
如果(this.nextConn>=this.connCount)
this.nextConn=0;
});
设sioProps=['sockets'];
sioProps.forEach(prop=>{//将所有socket.io属性从第一个实例映射到“this[prop]”
这个[prop]=这个;
});
让sioMethods=['seveClient'、'path'、'adapter'、'origins'、'attach'、'listen'、'bind'、'onconnection'、'of'、'close'];
forEach(fName=>{//将所有socket.io函数调用重定向到所有socket.io实例
此[fName]=()=>{
这是.\u io.forEach(io=>{
此[fName]=io[fName](…参数);
});
};
});
}
}
module.exports=ServerWrapper;

当前无法通过WebRTC从浏览器启动任意UDP连接。有一个

然而,浏览器插件当然可以使用UDP,因此如果这是一个可以接受的路径,那么您的应用程序可能需要使用插件来解决这种情况

预构建的解决方案有一些选项,这里有一个特别的选项:

是一个面向游戏开发人员的网络代码库,它实现了TCP over UDP的一些相同的面向连接的逻辑,但没有可交付性保证

是一个可用于Firefox和Chrome的浏览器插件,允许您使用netcode.io而无需开发自己的浏览器扩展

希望这有帮助。

该项目提供了一个围绕优秀WebRTC库的socket.io接口。如果您的应用程序是实时的,并且能够容忍消息无序到达,那么您应该能够执行类似操作来禁用排序保证(以防止丢失/延迟的消息延迟以后的消息):


为了帮助查找文档,请注意,
peerOpts
值成为SimplePeer对象从SimplePeer到SimplePeer的值。

我已经看过这篇文章了,老实说,我发现关于UDP的部分非常糟糕。(大量错误信息。)顺便说一句,我不想使用浏览器插件。我不知道你所说的任意UDP连接是什么意思,但WebRTC允许通过UDP进行通信。
let peerOpts = {channelConfig: {ordered: false}}
let p2psocket = new P2P(socket, peerOpts)