sending OSC between machines on a LAN using Node.js and OSC.js - node.js

Has anyone created a working setup where OSC is being sent between machines on a LAN using Node.js? Ideally, using Colin Clark's osc.js package?
I have what I think should be a pretty simple example, except that it doesn't work - I get an EADDRNOTAVAIL error, which implies that the remote address isn't available. I can ping the other laptop successfully, however.
Here's the code and the error, for reference:
Sending code (laptop at 192.168.0.5):
var osc = require("osc");
var udp = new osc.UDPPort({
localAddress: "127.0.0.1", // shouldn't matter here
localPort: 5000, // not receiving, but here's a port anyway
remoteAddress: "192.168.0.7", // the other laptop
remotePort: 9999 // the port to send to
});
udp.open();
udp.on("ready", function () {
console.log("ready");
setInterval(function () {
udp.send({
address: "/sending/every/second",
args: [1, 2, 3]
})
}, 1000);
});
Receive code (on laptop at 192.168.0.7):
var osc = require("osc");
var udp = new osc.UDPPort({
localAddress: "192.168.0.7",
localPort: 9999
});
udp.open();
udp.on("ready", function () {
console.log("receiver is ready");
});
udp.on("message", function(message, timetag, info) {
console.log(message);
});
Here's the error I get when I run the sending code:
ready
events.js:141
throw er; // Unhandled 'error' event
^
Error: send EADDRNOTAVAIL 192.168.0.7:9999
at Object.exports._errnoException (util.js:907:11)
at exports._exceptionWithHostPort (util.js:930:20)
at SendWrap.afterSend [as oncomplete] (dgram.js:345:11)

The issue is that the osc.UDPPort that you are using to send OSC messages has its localAddress bound to the loopback address, which is limited to connections within your local computer. As a result, your sender can't find your receiver.
The solution is to bind your sender's localAddress to an appropriate network interface. If your 192.168.0.5 IP address is stable and you don't need to worry about it changing when you connect your laptops to another network (say, for a gig or a gallery installation), then you can just use that. Otherwise, you might want to use an mDNS name ("foo.local") or the "all interfaces" address, 0.0.0.0.
This change to your "Sender code" worked for me when I tried it on my network:
var osc = require("osc");
var udp = new osc.UDPPort({
localAddress: "0.0.0.0", // Totally does matter here :)
localPort: 5000,
remoteAddress: "192.168.0.7", // the other laptop
remotePort: 9999 // the port to send to
});
udp.open();
udp.on("ready", function () {
console.log("ready");
setInterval(function () {
udp.send({
address: "/sending/every/second",
args: [1, 2, 3]
})
}, 1000);
});
As a side note, osc.js's behaviour does differ from a regular Node.js UDP socket, since if the local address is omitted Node will default to 0.0.0.0. An osc.UDPPort, however, will always bind to 127.0.0.1 if localAddress is omitted (which seemed a little safer to me when originally implementing osc.js, but I can see how it might be confusing).
This issue is also discussed on the osc.js issue tracker, and I will update the documentation to prevent the kind of confusion you encountered here. Best of luck with your project!

Related

why does Chrome connect to my nodejs server from 2 ports?

my nodejs script is:
const http = require("http");
const httpserver = http.createServer();
httpserver.on('connection', socket=>{
console.log(socket.remotePort, socket.address());
})
httpserver.listen(8080)
when navigating to the url: http://localhost:8080/ in Chrome I see that 2 connections are established on consecutive remote ports ex:
55413 {address: '::1', family: 'IPv6', port: 8080}
55414 {address: '::1', family: 'IPv6', port: 8080}
I'm confused as to why it is establishing 2 connections. Other browsers don't do this. Any thoughts are greatly appreciated. Thanks
I updated the node code to the following:
const http = require("http");
const httpserver = http.createServer();
httpserver.on('connection', socket=>{
console.log(socket.remotePort, socket.address());
socket.on('data',(data)=>{
console.log(socket.remotePort, socket.bytesRead);
console.log(data.toString())
})
socket.on('end',(data)=>{
console.log(socket.remotePort, 'ended');
})
})
httpserver.on('request', (req,res)=>console.log('request is made made'));
httpserver.listen(8080);
after refreshing the page a few times it seems that Chrome establishes 2 socket connections and uses the first to receive the GET request. The second receives no data. Upon refresh of the page it ends the first socket connection ( that was used for the GET request); opens a new socket connection (3rd) then uses the 2nd created for the new GET request. On each consecutive refresh it creates a new socket connection and uses the previous opened one, while ending the socket used for the previous GET request.
So it seems Chrome is creating a second socket in anticipation of a page refresh?

Node : how to set static port to udp client in node js

I am very new to Udp Socket programming, here i implemented echo UDP Client which connects to UDP server
var buffer = require('buffer');
var udp = require('dgram');
// creating a client socket
var client = udp.createSocket('udp4');
//buffer msg
var data = Buffer.from('Pradip Shinde');
client.on('message',function(msg,info){
console.log('Data received from server : ' + msg.toString());
console.log('Received %d bytes from %s:%d\n',msg.length, info.address, info.port);
});
//sending msg
client.send(data,9300,'192.168.1.187',function(error){
if(error){
client.close();
}else{
console.log('Data sent from client!!!');
}
});
when this client send msg to server, operating system assign the random port to this client but in my scenario i want static port which will never change, is it possible to assign static port to udp client?
As mentioned in the documentation, you can use bind method to do this,
For UDP sockets, causes the dgram.Socket to listen for datagram messages on a named port and optional address that are passed as properties of an options object passed as the first argument. If port is not specified or is 0, the operating system will attempt to bind to a random port. If address is not specified, the operating system will attempt to listen on all addresses. Once binding is complete, a 'listening' event is emitted and the optional callback function is called.
Try using
// Creating a client socket
var client = udp.createSocket('udp4');
// Bind your port here
client.bind({
address: 'localhost',
port: 8000,
exclusive: true
});
For more information follow this documentation.

Print-Server written with Electron/Node.js

I'm trying to create a print-server written with electron and node js.
My goal is to catch the body of a print-job from a POS to an Epson thermal printer.
As I understood correctly from the documentations of Epson, the printer communicates on tcp port 9100 and on udp 3289 by default.
So I created a websocket which is listening on the tcp port with the "Net" module.
The socket is established successfully and I also recieve some Buffer data.
My Question for now is, how can I encode this buffer, as it isn't possible to encode this via the default encoding types from Node.js.
Or would you recommend to use a virtual printer which prints a file and afterwards to try reading the data from it?
Which module or virtual printers are recommended?
I've searched already for quite a while now without finding any positive results.
Here is my current code from the net server:
var server = net.createServer(function(socket) {
socket.setEncoding('utf8')
socket.on('data', function(buffer) {
var decoded = buffer
console.log(decoded)
})
socket.on('end', socket.end)
});
server.on('connection', handleConnection);
server.listen(9100, function() {
console.log('server listening to %j', server.address());
});
function handleConnection(conn) {
var remoteAddress = conn.remoteAddress + ':' + conn.remotePort;
console.log('new client connection from %s', remoteAddress);
conn.on('data', onConnData);
conn.once('close', onConnClose);
conn.on('error', onConnError);
}
Ok I've got this running.
The Problem was, that the cashing system first made a request for the printerstatus "DLE EOT n".
So I responded to the cashing system with the according status bits / byte (0x16).
Afterwards the POS sended the printjob which I decoded from CP437 to UTF8 to capture and to be able to let my script read the incoming printrequest.
Hope this post helps anyone who is developing anything similar like kitchen monitors, printservers etc. as I found very less informations in the web about this topic.

nodejs NET api bug? Seeking flawless reconnect fix

I think there may be an issue with the Nodejs v5.3.0 NET api. I am wanting to rely on the socket.remoteAddress field flipping to undefined when the socket is destroyed.
socket.remoteAddress
The string representation of the remote IP address. For example, '74.125.127.100' or '2001:4860:a005::68'. Value may be undefined if the socket is destroyed (for example, if the client disconnected).
The challenge here is the may language above (bold added for emphasis).
Context: I'm writing a MEaN app that uses sockets to communicate with a remote deviec. The connection is often disconnected and I need to seamlessly reconnect it before use. I have the various functions needed to transmit call connect() before they want to transmit to ensure the connection is live.
UPDATED WITH FIX per mscdex:
if ( !client.readable )
client.connect(PORT,HOST);
else
logger.debug('Attempt to reconnect on an active connection. Ignored.');
client.readable provides immediate status on the network connection even if the intent is to write to the connection. client.writable is buffered and thus 'lies' (is overly optimistic) about the connection being present or able to be established.
The below is working code:
var logger = require('winston');
var net = require('net');
var client = new net.Socket();
var init = function() {
logger.info('Calling connect now...' );
connect();
};
exports.init = init;
var output = function(action, id) {
connect();
//Transmit stuff here
};
exports.output = output;
var connect = function() {
// Check to see if remoteAddress is undefined. If so, then connect
logger.debug('Test if connection is active: ' + client.remoteAddress);
if ( typeof (client.remoteAddress) == 'undefined' ) {
client.connect( 2101, '10.10.10.4', function() {
logger.info('Connection now open');
});
}
else {
logger.debug('Attempting reconnect on active connection. Ignore: ' + client.remoteAddress);
}
};
// This events, as expected, when the VPN is connected and data is received.
client.on('data', function() {
logger.debug('Data incoming');
});
// This events, as expected, when the VPN drops
client.on('error', function() {
logger.debug('Connection error so destroy() the client');
client.destroy();
// I *was* expecting destroy() to make typeof (client.remoteAddress) = 'undefined'. It does not.
});
Here's what the resultant log looks like
info: Calling connect now...
debug: Test if connection is active: undefined
info: Connection now open
debug: Data incoming
debug: Data incoming
debug: Test if connection is active: 10.10.10.4
debug: Attempting reconnect on active connection. Ignore: 10.10.10.4
POST /elk/output 200 18.122 ms - 2
debug: Data incoming
I disconnected the VPN
debug: Test if connection is active: 10.10.10.4
debug: Attempting reconnect on active connection. Ignore: 10.10.10.4
POST /elk/output 200 1.546 ms - 2
debug: Connection error so destroy() the client
Now, given the client.destroy(); call, I'd expect client.remoteAddress to become undefined per document but it is not.
debug: Test if connection is active: 10.10.10.4
debug: Attempting reconnect on active connection. Ignore: 10.10.10.4
debug: Connection error so destroy() the client
POST /elk/output 200 1.063 ms - 2
Thoughts?
Thanks
Don't use remote ip to detect if the remote connection has been disconnected. Instead, subscribe to the close event (and depending on the use case, maybe the end event as well):
client.on('close',function(){
// client has been disconnected.
connect();
});
client.on('end',function(){
// client wants to disconnect.
connect();
});
To really close the socket you can set the close (and end) handlers to do nothing:
client.on('close',function(){});
client.destroy();
You could also check if the TCP stream is readable or not by checking client.readable.

Non-http TCP connection on Cloudfoundry

I'm a nooby mobile developer trying to take advantage of cloudfoundry's service to run my server to handle some chats and character movements.
I'm using Noobhub to achieve this (TCP connection between server and client using Node.js and Corona SDK's TCP connection API)
So basically I'm trying a non-http TCP connection between Cloudfoundry(Node.js) and my machine(lua).
Link to Noobhub(There is a github repo with server AND client side implementation.
I am doing
Client
...
socket.connect("myappname.cloudfoundry.com", 45234)
...
(45234 is from server's process.env.VCAP_APP_PORT value I retrieved from console output I got through "vmc logs myappname" after running the application.)
Server
...
server.listen(process.env.VCAP_APP_PORT)
When I try to connect, it just times out.
On my local machine, doing
Client
...
socket.connect("localhost",8989)
Server
...
server.listen(8989)
works as expected. It's just on cloudfoundry that it doesn't work.
I tried a bunch of other ways of doing this such as setting the client's port connection to 80 and a bunch of others. I saw a few resources but none of them solved it.
I usually blow at asking questions so if you need more information, please ask me!
P.S.
Before you throw this link at me with an angry face D:< , here's a question that shows a similar problem that another person posted.
cannot connect to TCP server on CloudFoundry (localhost node.js works fine)
From here, I can see that this guy was trying to do a similar thing I was doing.
Does the selected answer mean that I MUST use host header (i.e. use http protocol) to connect? Does that also mean cloudfoundry will not support a "TRUE" TCP socket much like heroku or app fog?
Actually, process.env.VCAP_APP_PORT environment variable provides you the port, to which your HTTP traffic is redirected by the Cloud Foundry L7 router (nginx) based on the your apps route (e.g. nodejsapp.vcap.me:80 is redirected to the process.env.VCAP_APP_PORT port on the virtual machine), so you definitely should not use it for the TCP connection. This port should be used to listen HTTP traffic. That is why you example do work locally and do not work on Cloud Foundry.
The approach that worked for me is to listen to the port provided by CF with an HTTP server and then attach Websocket server (websocket.io in my example below) to it. I've created sample echo server that works both locally and in the CF. The content of my Node.js file named example.js is
var host = process.env.VCAP_APP_HOST || "localhost";
var port = process.env.VCAP_APP_PORT || 1245;
var webServerApp = require("http").createServer(webServerHandler);
var websocket = require("websocket.io");
var http = webServerApp.listen(port, host);
var webSocketServer = websocket.attach(http);
function webServerHandler (req, res) {
res.writeHead(200);
res.end("Node.js websockets.");
}
console.log("Web server running at " + host + ":" + port);
//Web Socket part
webSocketServer.on("connection", function (socket) {
console.log("Connection established.");
socket.send("Hi from webSocketServer on connect");
socket.on("message", function (message) {
console.log("Message to echo: " + message);
//Echo back
socket.send(message);
});
socket.on("error", function(error){
console.log("Error: " + error);
});
socket.on("close", function () { console.log("Connection closed."); });
});
The dependency lib websocket.io could be installed running npm install websocket.io command in the same directory. Also there is a manifest.yml file which describes CF deploy arguments:
---
applications:
- name: websocket
command: node example.js
memory: 128M
instances: 1
host: websocket
domain: vcap.me
path: .
So, running cf push from this directory deployed app to my local CFv2 instance (set up with the help of cf_nise_installer)
To test this echo websocket server, I used simple index.html file, which connects to server and sends messages (everything is logged into the console):
<!DOCTYPE html>
<head>
<script>
var socket = null;
var pingData = 1;
var prefix = "ws://";
function connect(){
socket = new WebSocket(prefix + document.getElementById("websocket_url").value);
socket.onopen = function() {
console.log("Connection established");
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log("Connection closed clean");
} else {
console.log("Connection aborted (e.g. server process killed)");
}
console.log("Code: " + event.code + " reason: " + event.reason);
};
socket.onmessage = function(event) {
console.log("Data received: " + event.data);
};
socket.onerror = function(error) {
console.log("Error: " + error.message);
};
}
function ping(){
if( !socket || (socket.readyState != WebSocket.OPEN)){
console.log("Websocket connection not establihed");
return;
}
socket.send(pingData++);
}
</script>
</head>
<body>
ws://<input id="websocket_url">
<button onclick="connect()">connect</button>
<button onclick="ping()">ping</button>
</body>
</html>
Only thing to do left is to enter server address into the textbox of the Index page (websocket.vcap.me in my case), press Connect button and we have working Websocket connection over TCP which could be tested by sending Ping and receiving echo. That worked well in Chrome, however there were some issues with IE 10 and Firefox.
What about "TRUE" TCP socket, there is no exact info: according to the last paragraph here you cannot use any port except 80 and 443 (HTTP and HTTPS) to communicate with your app from outside of Cloud Foundry, which makes me think TCP socket cannot be implemented. However, according to this answer, you can actually use any other port... It seems that some deep investigation on this question is required...
"Cloud Foundry uses an L7 router (ngnix) between clients and apps. The router needs to parse HTTP before it can route requests to apps. This approach does not work for non-HTTP protocols like WebSockets. Folks running node.js are going to run into this issue but there are no easy fixes in the current architecture of Cloud Foundry."
- http://www.subbu.org/blog/2012/03/my-gripes-with-cloud-foundry
I decided to go with pubnub for all my messaging needs.

Resources