Не удалось отправить сообщения OSC с пакетом 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)

Я запускаю OSCulator на OSX в качестве сервера. Код выше живет на другой машине. Когда я бегу nmap на IP-адресе порт открыт:

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 ответа

Я знаю, что прихожу к этому довольно поздно, и похоже, что вы нашли другую библиотеку, которая работает для вас, но я подумал, что ответ может быть полезен для других, кто сталкивается с этой проблемой. Я разработчик osc.js, оригинальной библиотеки, которую вы пытались использовать.

Прежде всего, в качестве справочной информации, osc.js делится на два разных слоя:

  1. Низкоуровневый API, обеспечивающий функции для чтения и записи сообщений и пакетов OSC в / из Typed Arrays.
  2. Высокоуровневый, основанный на событиях API-интерфейс порта, который предоставляет коллекцию транспортных объектов, специфичных для платформы, которые обеспечивают простой способ двунаправленной связи по таким протоколам, как UDP, веб-сокеты и т. Д.

В случае вашего примера кода вы пытались отправить сообщение OSC на ваш UDPPort объект до того, как он будет готов. Когда ты 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 иллюстрирует этот шаблон. Но когда я увидел ваш вопрос, я понял, что пример кода в файле README для osc.js был немного двусмысленным в этом отношении. Я улучшил документацию о событии и встроенный пример кода README, чтобы быть более ясным в этом отношении. Извините за путаницу.

В некоторых случаях, например, у вас, высокоуровневый API не совсем то, что вам нужно. osc.js также предоставляет функции для легкого кодирования пакета OSC как Uint8Array, который может быть преобразован в буферы Node.js. Таким образом, вы могли бы сделать что-то похожее на ваше решение, просто используя osc.js osc.writeMessage() функция. К счастью, это всегда было хорошо документировано. Вот ваш пример, модифицированный для использования низкоуровневого API osc.js:

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.

С уважением и извинениями за проблемы, с которыми вы столкнулись при использовании библиотеки!

Я подумал, что на самом деле довольно легко отправлять данные OSC через UDP без необходимости каких-либо пакетов, кроме 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);
Другие вопросы по тегам