使node.js及时发送数据报套接字数据

时间:2013-09-10 11:05:54

标签: javascript node.js sockets datagram node-webkit

我有一个基于Node-Webkit的应用程序,它执行一些繁重的WebGL工作(足以强调高端GPU),相当大量的JS处理,我正在发送OSC数据节点dgram模块~4kb / s的顺序到scsynth子进程来控制音频。

OSC数据每10帧动画包含在一个包中,音频相当容忍它收到的消息中的一些延迟或不规则,但不是我正在经历的规模。

不幸的是,我发现在调用socket.send(...)和实际发送数据之间存在很大的延迟。似乎在某些情况下,调度程序将实际发送数据的优先级设置得非常低,以至于每个新数据包几乎无限期地陷入停顿状态,然后突然在溢出scsynth命令队列的大量不受控制的突发中释放。

我无法将udp代码放入WebWorker中,因为node.js对象在该上下文中不起作用。我正在考虑尝试设置一个单独的窗口(因此,进程),单独负责将通过window.postMessage接收的数据转发到UDP(反之亦然),但由于postMessage本身也是异步的,如果它不可见,那么另一个窗口本身可能具有低优先级,我想知道这是否可能提供很多好处。

我很确定主要问题在于在Javascript中安排工作而不是在流程中的其他任何地方;我认为在接收端没有特别的麻烦,尽管可能会对此进行更密切的评估。

这是一个简短的片段,展示了如何设置和使用套接字(包括在发送回调上收集一些基本统计信息)。

udp = require('dgram').createSocket('udp4');
//...
var udpStats = {lastSendDelay: 0, minSendDelay:Number.MAX_VALUE, maxSendDelay:-1, meanSendDelay:undefined};
var udpSend = function(buf) {
    var t = new Date();
    var wasSent = function(timeOfRequest) {
        return function(err) {
            if ((err)) sclog("UDP send Error: " + err);
            var t2 = new Date();
            var dt = t2 - timeOfRequest;
            udpStats.lastSendDelay = dt;
            udpStats.minSendDelay = Math.min(dt, udpStats.minSendDelay);
            udpStats.maxSendDelay = Math.max(dt, udpStats.maxSendDelay);
            udpStats.meanSendDelay = udpStats.meanSendDelay === undefined ? dt : (udpStats.meanSendDelay+dt)/2;
        };
    };

    udp.send(buf, 0, buf.length, UDP_PORT, 'localhost', wasSent(t));
};

1 个答案:

答案 0 :(得分:1)

如果它可以帮助其他人,我们通过将对requestAnimationFrame的调用替换为超时1ms的调用和requestAnimationFrame来解决这个问题。这允许其他东西(例如udp发送/接收处理)在1ms dealy中挤入线程,而不会显着影响整体fps。

~~~

P.S。 使用nw 8.5我发现使用setTimeout延迟requestAnimationFrame效果最好,典型的OSC往返时间为2ms。延迟使用process.setTick给OSC的往返时间约为20ms。直接调用requestAnimationFrame会导致几乎完整的OSC消息块。

使用nw 12.1没有问题,并且所有三种变体表现几乎完全相同,典型的往返时间为2ms。

由于我们的webGL代码无法与ANGLE一起使用,因此我们一直被限制使用nw 8.5,而后续版本的nw不适用于-use-gl = desktop。使用最新版本的nw,ANGLE工作得更好,而-use-gl = desktop也在使用。