无法使用节点的osc包发送OSC消息。端口关闭错误,即使机器上的端口已打开

时间:2016-08-30 09:34:21

标签: node.js osc

我正在使用以下代码尝试将OSC消息发送到网络上的计算机。我正在使用名为osc的包。

我无法向运行OSC服务器的计算机发送消息,并在尝试发送OSC消息时收到以下错误:

Error: Uncaught, unspecified "error" event. (Can't send packets on a closed osc.Port object. Please open (or reopen) this Port by calling open().)

代码

let osc = require('osc');

let oscUDP = new osc.UDPPort({
    remoteAddress: "192.168.1.5",
    remotePort: 8004
});

oscUDP.send({
    address: "/carrier/frequency",
    args: 440
});

oscUDP.open();

如果我在oscUDP.open()来电之前放send,我会收到其他错误:

Error: send EINVAL 192.168.1.5:8004
at Object.exports._errnoException (util.js:1007:11)
at exports._exceptionWithHostPort (util.js:1030:20)
at SendWrap.afterSend [as oncomplete] (dgram.js:402:11)

我在OSX上运行OSCulator作为服务器。上面的代码位于不同的机器上。当我在IP地址上运行nmap时,端口是打开的:

nmap 192.168.1.5 -p 8004

Starting Nmap 6.40 ( http://nmap.org ) at 2016-08-30 08:22 BST
Nmap scan report for 192.168.1.5
Host is up (0.13s latency).
PORT     STATE  SERVICE
8004/tcp open unknown

如果我使用osc-cli,则在运行OSC服务器的计算机上收到消息:

osc --host 192.168.1.5:8004 /test 1 2 3

因此,当使用osc-cli时发送和接收消息时,似乎问题不在于封闭端口。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

我知道我很晚才到这里,看起来你找到了一个适合你的不同的图书馆,但我认为回复可能对面临这个问题的其他人有所帮助。我是osc.js的开发者,这是您尝试使用的原始库。

首先,作为背景信息,osc.js被分解为两个不同的层:

  1. 低级API,提供读取和写入类型化数组的OSC消息和包的功能。
  2. 更高级别的基于事件的端口API,它提供了一组特定于平台的传输对象,它提供了一种通过UDP,Web套接字等协议进行双向通信的简便方法。
  3. 对于示例代码,您尝试在UDPPort对象准备好之前发送OSC消息。当您open() Port时,它可能需要执行异步操作,例如打开套接字等。因此,它会在端口触发事件(恰当地称为ready)已全部设定使用。在ready触发之前,您将无法发送或接收OSC数据包。

    因此,对于原始代码,看起来您假设此行是同步的,之后您可以立即调用send()

    oscUDP.open();
    

    相反,在尝试在ready上发送消息之前,您只需要监听Port事件。像这样:

    oscUDP.on("ready", function () {
        oscUDP.send({
            address: "/carrier/frequency",
            args: 440
        });
    });
    

    osc.js Node.js example说明了这种模式。但是当我看到你的问题时,我意识到osc.js自述文件中的示例代码在这方面有点含糊不清。我有improved the event documentationthe inline README sample code在这方面更加明确。对不起,感到困惑。

    有些情况,例如您的情况,更高级别的API并不是您所需要的。 osc.js还提供了将OSC数据包轻松编码为Uint8Array的功能,可将其转换为Node.js缓冲区。因此,只需使用osc.js'osc.writeMessage()函数,就可以完成与解决方案类似的操作。幸运的是,它一直都有很好的记录。以下是您的示例,修改为使用osc.js的低级API:

    const dgram = require('dgram');
    const client = dgram.createSocket('udp4');
    const osc = require('osc');
    
    const HOST = '192.168.1.5';
    const PORT = 8004;
    
    process.on('SIGINT', function() {
      client.close();
    });
    
    let oscNoteMessage = function(note, value) {
      var message = osc.writeMessage({
          address: '/note/' + note,
          args: [
              {
                  type: 'i',
                  value: value
              }
          ]
        });
    
      return Buffer.from(message);
    }
    
    let noteOn = function(note) {
      return oscNoteMessage(note, 1);
    }
    
    let noteOff = function(note) {
      return oscNoteMessage(note, 0);
    }
    
    let send = function(message) {
      client.send(message, PORT, HOST, function(err, bytes) {
        if(err) throw new Error(err);
      })
    }
    
    send(noteOn('c'));
    setTimeout(function() {
      send(noteOff('c'));
    }, 1000);
    

    无论如何,我很高兴您能够提出适用于您的项目的解决方案,我希望此响应可以帮助可能遇到类似问题的其他用户。当然,您可以在osc.js issue tracker上提出问题或提出问题。

    致以最诚挚的问候,并为您使用该库遇到的麻烦道歉!

答案 1 :(得分:1)

我认为通过UDP发送OSC数据实际上很容易,而不需要除a2r-osc之外用于编码OSC数据的任何软件包。

我正在发布解决方案,感兴趣的是其他任何人:

const dgram = require('dgram');
const client = dgram.createSocket('udp4');
const osc = require('a2r-osc');

const HOST = '192.168.1.5';
const PORT = 8004;

process.on('SIGINT', function() {
  client.close();
});

let noteOn = function(note) {
  return new osc.Message('/note/' + note, 'i', 1).toBuffer();
}

let noteOff = function(note) {
  return new osc.Message('/note/' + note, 'i', 0).toBuffer();
}

let send = function(message) {
  client.send(message, PORT, HOST, function(err, bytes) {
    if(err) throw new Error(err);
  })
}

send(noteOn('c'));
setTimeout(function() {
  send(noteOff('c'));
}, 1000);