Node : how to set static port to udp client in node js - 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.

Related

How to connect two mobile clients via UDP sockets

I want to make a UDP connection for voice calls between two applications. To decrease transactions over the server, I need to send the UDP packet directly from one client to another client without sending packets over the server. But I faced the below situation:
When a packet is sent to a server, the server will receive it from the router IP and a random port.
I tried to send a response from the server to the client through the router IP and port by opening a new UDP socket connection, but the client didn't receive the response.
I do the same by sending my response over the socket that already received the client message, and this time it received the client.
I failed to send UDP packets from other UDP sockets (both on the server and other clients) to my first client, even over the router IP and opened port on it.
I'm curious to know if it is possible to make client-to-client UDP connection or not?
The below code is the correct model to return respond to the client:
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.on('message', (msg, rinfo) => {
console.log(`* server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
const message = Buffer.from('Some bytes to '+rinfo.address+":"+rinfo.port);
//////↓///////////This is the receiver socket
server.send(message, rinfo.port, rinfo.address);
//////↑///////////
});
server.bind(8090);
By the below code, the client will not receive any response, even from the server which received the client message right now!
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const serverResponse = dgram.createSocket('udp4');
server.on('message', (msg, rinfo) => {
console.log(`* server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
const message = Buffer.from('Some bytes to '+rinfo.address+":"+rinfo.port);
///////↓///////// This is the different socket instance
serverResponse .send(message, rinfo.port, rinfo.address);
///////↑//////////
});
server.bind(8090);
is this true? "you send a message from your client and the server receive it but when you send response to your client the client did not receive the response".
If this is true then i think that you need use a same socket object for sending and receiving because you cannot create two socket object over same port on a device.

Serve flash policy requests on port 80 beside HTTP in node.js

I want to serve socket connections from a Flash browser client, and therefore I need to add support for the policy-request-file protocol. I can't run the policy-file-request service on the default port 843 because of firewalls etc. The only option I have is to server the protocol on port 80, beside my HTTP server.
My app is written in node.js and the following code works:
var httpServer = http.createServer();
net.createServer(function(socket){
httpServer.emit('connection', socket);
}).listen(80);
I open a socket server on port 80, and for now I just emit the connection event on the httpServer, no problem so far. Now I want to check if the new socket is a policy-file-request which will just send the plain string <policy-file-request /> over a TCP connection. When I notice this string I know it isn't HTTP and I can return the crossdomain file and close the socket. So what I try now is this:
net.createServer(function(socket){
socket.once('readable', function(){
var chunk = socket.read(1);
// chunk[0] === 60 corresponds to the opening bracket '<'
if(chunk !== null && chunk[0] === 60) {
socket.end(crossdomain);
} else {
socket.unshift(chunk);
httpServer.emit('connection', socket);
}
});
}).listen(80);
Now I check if the first byte is the opening bracket '<' and then write the crossdomain file to the socket. Otherwise I unshift the chunk onto the stream and emit the socket as a connection on the HTTP-server. Now the problem is that the HTTP-server doesn't emit a request event anymore and my regular HTTP-requests aren't handled as a result.
I also tried this solution but with no success either:
httpServer.on('connection', function(socket){
socket.once('data', function(chunk){
if(chunk[0] === 60) {
socket.end(crossdomain);
}
})
});
When the socket emits the data event, the readyState of the socket is already 'closed' and a clientError event is already thrown by the httpServer. I searched everywhere and didn't found a solution. I also don't want to pipe the data through another socket to another port where my HTTP server is running locally, because that adds to many, unnecessary overhead I think. Is there a clean way to do this in node.js? I tested all this on node.js version 0.10.26.

Can not send back UDP to internal PC behide NAT

I setup two PC,
one is client in local network behide NAT,
another is server on public network.
The test steps are --
1) client listen udp on port 33333
2) server listen udp on port 22222
1) client send udp to server
2) server received the data and send back
When I test the code on my test network, it's OK.
If put the server on real internet, server can get the message from client,
client can not get response from server.
What's wrong?
Here's testing code with nodejs.
server
var dgram = require('dgram');
var socket = dgram.createSocket('udp4');
socket.on('message', function (message, remote) {
console.log('client ip:' + remote.address + ', port:' + remote.port +', message:' + message);
//send response to client
var message = new Buffer("hello, client!");
socket.send(message, 0, message.length, remote.port, remote.address);
});
//listening port
socket.bind(22222);
client
var dgram = require('dgram');
var socket = dgram.createSocket('udp4');
socket.on('message', function (message, remote) {
//display message from server
console.log('server ip:' + remote.address + ', port:' + remote.port +', message:' + message);
});
//listening port
socket.bind(33333);
//send message to server
function send(server){
var message = new Buffer("hello, server!");
socket.send(message, 0, message.length, 22222, server, function(){
//send again after 1 seconds
setTimeout(function(){
send(server);
}, 1000);
});
};
//suppose that server address is public.server.com
send("public.server.com");
NATed computers cannot be reached from outside and this is particularly painful for peer-to-peer or friend-to-friend software. Basically because your PC has not a public IP address but you NAT device has. So, the NAT is visible, your PC isn't.
The server gets the package from the NAT device and send the response to it. Yes, the NAT receives the response and it has to relay it to your PC, that's the trick. To do so you have to configure a port forwarding in the NAT.
The NAT has a table like the following:
+----------+---------------------+---------------+
| NAT PORT | INTERNAL IP ADDRESS | INTERNAL PORT |
+----------+---------------------+---------------+
| 33333 | 198.162.0.3 (pc ip) | 33333 |
It can be read as: when NAT receives a package in its port #33333 it has to redirected to the internal IP 198.162.0.3 (your PC IP address) and port# 33333.
If your PC uses a fixed IP, you can do this mapping by hand in your NAT. However, if you use a DHCP server, your PC's IP can change after each reboot so you need to do this mapping by software in you project. Most of the NATs support Universal Plug & Play, Port Mapping Protocol or Port Control Protocol to achieve this mapping and you can do it with nodejs given that all you need are the appropiated HTTP request to the NAT.
Yes, you can do it by yourself but it is not so easy. In fact, the discovery process requires you broadcast udp messages in the LAN in specific port. I strongly recommend you to use a third-party component to do it.
I hope this helps you.

TCP and WEB sockets

I have http server and socket.io (listening this http server). Clients connect(via socket io) and get some information. Now I want to have clients connecting via tcp socket that will receive the same information as the clients on web socket. How to do it? Is it required to create a net server? And if so, then how information which come to http server send to tcp clients?
You need to create the TCP server so clients will be able to connect to it.
One solution can be using a messaging system (such as pub/sub with Redis, or a library like https://github.com/learnboost/kue) to notify the other server to send the data.
For example:
1) user connects to socket.io
2) user connects to TCP server
3) TCP server subscribes to listening to signals
4) socket.io emits data to the user and signals the TCP server to send the data as well
5) TCP server sends the data
in nodejs to start a tcp server:
var fs = require('fs');
var net = require('net');
var server = net.createServer(function(socket){ // create a tcp server
socket.on('data',function(data){ // on data event when data is set to the socket
var strRequestInfo = data.toString(); // get the string sent by the client
/*
here you could analyse the request data
and think what to do with it like return a certain file
*/
fs.readFile('/path/to/some/file.html', function (err, fileData) { // read a file
if (err) throw err;
socket.write(fileData); // write file content to tcp socket
});
/* -or- just write some text */
socket.write(new Buffer('some text'));
});
});
server.listen(8080, function() { // bind the server
console.log('TCP server bound');
});
you have to take in to consideration that socket.on('data') will not trigger when all the data is sent, it can trigger many time depending on the size of the data being sent.
Therefore the request data should be concatenated until the logic of your request decides to send a response back to the client.
You can add the sockets to an array if you would like to send data to all sockets:
var socketArray =[];
var server = net.createServer(function(socket){
socketArray.push(socket);
});
then you could iterate and send responses to all client:
for(var i=0;i<socketArray.length;i++)
socketArray[i].write(new Buffer('some data'));

Is it possible to enable tcp, http and websocket all using the same port?

I am trying to enable tcp, http and websocket.io communication on the same port. I started out with the tcp server (part above //// line), it worked. Then I ran the echo server example found on websocket.io (part below //// line), it also worked. But when I try to merge them together, tcp doesn't work anymore.
SO, is it possible to enable tcp, http and websockets all using the same port? Or do I have to listen on another port for tcp connections?
var net = require('net');
var http = require('http');
var wsio = require('websocket.io');
var conn = [];
var server = net.createServer(function(client) {//'connection' listener
var info = {
remote : client.remoteAddress + ':' + client.remotePort
};
var i = conn.push(info) - 1;
console.log('[conn] ' + conn[i].remote);
client.on('end', function() {
console.log('[disc] ' + conn[i].remote);
});
client.on('data', function(msg) {
console.log('[data] ' + conn[i].remote + ' ' + msg.toString());
});
client.write('hello\r\n');
});
server.listen(8080);
///////////////////////////////////////////////////////////
var hs = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Type' : 'text/html'
});
res.end(['<script>', "var ws = new WebSocket('ws://127.0.0.1:8080');", 'ws.onmessage = function (data) { ws.send(data); };', '</script>'].join(''));
});
hs.listen(server);
var ws = wsio.attach(hs);
var i = 0, last;
ws.on('connection', function(client) {
var id = ++i, last
console.log('Client %d connected', id);
function ping() {
client.send('ping!');
if (last)
console.log('Latency for client %d: %d ', id, Date.now() - last);
last = Date.now();
};
ping();
client.on('message', ping);
});
You can have multiple different protocols handled by the same port but there are some caveats:
There must be some way for the server to detect (or negotiate) the protocol that the client wishes to speak. You can think of separate ports as the normal way of detecting the protocol the client wishes to speak.
Only one server process can be actually listening on the port. This server might only serve the purpose of detecting the type of protocol and then forwarding to multiple other servers, but each port is owned by a single server process.
You can't support multiple protocols where the server speaks first (because there is no way to detect the protocol of the client). You can support a single server-first protocol with multiple client-first protocols (by adding a short delay after accept to see if the client will send data), but that's a bit wonky.
An explicit design goal of the WebSocket protocol was to allow WebSocket and HTTP protocols to share the same server port. The initial WebSocket handshake is an HTTP compatible upgrade request.
The websockify server/bridge is an example of a server that can speak 5 different protocols on the same port: HTTP, HTTPS (encrypted HTTP), WS (WebSockets), WSS (encrypted WebSockets), and Flash policy response. The server peeks at the first character of the incoming request to determine if it is TLS encrypted (HTTPS, or WSS) or whether it begins with "<" (Flash policy request). If it is a Flash policy request, then it reads the request, responds and closes the connection. Otherwise, it reads the HTTP handshake (either encrypted or not) and the Connection and Upgrade headers determine whether it is a WebSocket request or a plain HTTP request.
Disclaimer: I made websockify
Short answer - NO, you can't have different TCP/HTTP/Websocket servers running on the same port.
Longish answer -
Both websockets and HTTP work on top of TCP. So you can think of a http server or websocket server as a custom TCP server (with some state mgmt and protocol specific encoding/decoding). It is not possible to have multiple sockets bind to the same port/protocol pair on a machine and so the first one will win and the following ones will get socket bind exceptions.
nginx allows you to run http and websocket on the same port, and it forwards to the correct appliaction:
https://medium.com/localhost-run/using-nginx-to-host-websockets-and-http-on-the-same-domain-port-d9beefbfa95d

Resources