无序的WebSocket消息(不等待丢失数据包的重传)

10

当服务器发送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;
2个回答

1

socket.io-p2p 项目提供了一个围绕着优秀的simple-peer WebRTC库的socket.io接口。如果你的应用程序是实时的,并且可以容忍消息无序到达,那么你应该能够像这样做来禁用排序保证(以防止丢失/延迟的消息延迟后续消息):

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

为了帮助查找文档,请注意peerOpts值将成为来自simple-peer的SimplePeer对象的opts param

0

目前无法通过WebRTC从浏览器启动任意UDP连接。这里有一篇非常好的文章

然而,浏览器插件可以确实使用UDP通信 - 因此,如果这是一个可接受的方案,您的应用程序可以要求在此情况下使用插件。

有一些预构建解决方案可供选择,以下是其中之一:

netcode.io是一个面向游戏开发人员的netcode库,它实现了TCP上的一些相同的面向连接的逻辑,但没有交付保证。

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

希望这能帮到您。


我已经看过这篇文章了,说实话,关于UDP的部分真的很糟糕。(有很多错误信息。)顺便说一句,我不想使用浏览器插件。我不知道你所说的“任意UDP连接”是什么意思,但WebRTC允许通过UDP进行通信。 - Forivin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接