Find a free port that is not used for applications - find some kind of algorithm

I use the following API in my program to determine the free port and provide it to the application to run

portscanner.findAPortNotInUse(3000, 65000, '127.0.0.1', function(error, port) { console.log('AVAILABLE PORT AT: ' + port) }) 

https://github.com/baalexander/node-portscanner

This free port is provided for use by the application and works fine. The problem is that if I provide a free port for application A and the application is not already busy (sometimes it takes some time ...), another application B comes in and asks for a free port to give application A port B to APP B what is the cause of the problem ... is there an elegant way to solve it?

My application has no state, so it cannot save which application the port is connecting to ...

There is a solution that we can randomize the range, but this is not reliable ...

In my application Im getting the URL of the application, I have to provide a free port to run.

Update

I cannot use any broker or any other that will control this appearance. I need to find an algorithm (maybe with some smart random ones) that can help me do this internally, i.e. my program is similar to singleton, and I need some trick how to specify a port between 50000 to 65000 , which will reduce the number of port conflicts that was provided to applications

update 2

I decided to try something like the following, what do you think?

using lodash https://lodash.com/docs/4.17.2#random to define ports between loops that provide 3 (or more, if that makes sense) numbers for ranges like the following

 portscanner.findAPortNotInUse([50001, 60000, 600010], '127.0.0.1', function(err, port) { if(err) { console.log("error!!!-> " +err); }else { console.log('Port Not in Use ' + port); } //using that in a loop var aa = _.random(50000, 65000); 

Then, if I got a lie in the port, that is, all 3 ports are busy, run this process again for 3 other random offers .com numbers are welcome !!! I am trying to find a way to avoid a collision as much as possible ...

+5
source share
6 answers

When managing multiple applications or multiple servers, where everyone should be right for the first time (without retrying), you need a single source of truth. Applications on the same computer can talk to a database, broker server, or even to a file if the resource is "locked." (Servers work in a similar way, although not with local files).

So your thread will be something like this:

  • Appendix A sends a service request to request a lock.
  • When the lock is confirmed, start the port scanner
  • When using the port, release the lock.

Again, it could be the β€œPortService” you write to distribute unused ports or just block in some shared resource, so two things get the same port at the same time.

I hope you can find something suitable to work in your applications.

0
source

I would advise you to look for a way to maintain state. Even a temporary state, in memory, is better than nothing. That way, you could at least avoid issuing the ports you already issued. Because they are most likely not free. (It would be as simple as saving them and restoring a random port if you noticed that you found a random port that you already issued). If you do not want collisions, create your module so that it can be saved so that it can avoid them. If you do not want to do this, you will have to agree that sometimes collisions occur when they are not needed.

If the URLs you get are random, the best thing you can do is guess at random. If you can get some property in which the URLs are unique and consistently different, you can create something around this.

Code example:

 function getUnusedPort(url) { // range is [0, 65001). (inclusive zero, exclusive 65001) const guessPort = () => Math.floor(Math.random() * 15001) + 50000; let randomPort = guessPort(); while (checkPortInUse(randomPort)) { randomPort = guessPort(); } return randomPort; } 

Notes:

  • checkPortInUse is likely to be asynchronous, so you have to do this.
  • You said "between 50,000 and 65,000." This is from 50,000 to 65,000 inclusive.
0
source

If your applications can open ports with the SO_REUSEADDR parameter, but the operating system keeps the ports in the list in TIME_WAIT state, you can bind / open the port you want to return using SO_REUSEADDR, immediately close it and return it to the application. Thus, for the TIME_WAIT period (depending on the operating system, this can be 30 seconds, and the actual time must be determined / set or found by experiment / administration). A list of ports will show this port as busy.

If your port finder does not specify port numbers for ports in the TIME_WAIT state, the problem has been resolved with the relatively expensive open / close socket operation.

0
source

Have you tried something like this?

 var portscanner = require('portscanner') module.exports = function (ip, minport) { var pendings = []; var allocated = []; var pendingsearch = false; function start(){ if (!pendingsearch && pendings.length) { pendingsearch = true; var ready = pendings.shift(); var min = getMax(); min = min===-1?minport:min+1; var max = min + 100; portscanner.findAPortNotInUse(min, max, ip, function(err, port) { if (err) { pendings.unshift(ready); } else if (allocated.indexOf(port)>-1) { pendings.unshift(ready); } else { allocated.push(port); ready(port); } restart(); }) } } function restart(){ pendingsearch = false; setTimeout(start, 0); } function getMax(){ var max = -1; allocated.forEach(function(p) { if (p>max) { max = p } }) return max } function findPort(ready) { pendings.push(ready); start(); }; function updateAllocated() { var tocheck = [].concat(allocated); var todo = tocheck.length; tocheck.forEach(function(port, index) { portscanner.checkPortStatus(port, ip, function(error, status) { if (status==='closed') { allocated.splice(allocated.indexOf(port), 1); } if (index===tocheck.length-1) { setTimeout(updateAllocated, 1000); } }) }); if (tocheck.length<1) { setTimeout(updateAllocated, 1000); } }; var update = setTimeout(updateAllocated, 1000); return { findPort: findPort, stop: function(){ clearTimeout(update); }, } }; 
0
source

I would simply agree that everything can go wrong in a distributed system, and repeat the operation (i.e. get a free port) if for some reason it did not work on the first try.

Fortunately, there are many npm modules that do this for you, for example. retry .

Using this module, you can repeat the asynchronous operation until it succeeds, and also configure the wait strategies and how many times you need to repeat it as much as possible, and so on ...

To provide sample code, it basically boils down to the following:

 const operation = retry.operation(); operation.attempt(currentAttempt => { findAnUnusedPortAndUseIt(err => { if (operation.retry(err)) { return; } callback(err ? operation.mainError() : null); }); }); 

The advantages of this solution:

  • It works without blocking, that is, it uses resources efficiently and little if everything is in order.
  • Works without a central broker or something like that.
  • Works for distributed systems of any size.
  • Uses a pattern that you can reuse in distributed systems for all kinds of problems.
  • Uses a time-tested and reliable npm module instead of handwriting all of these things.
  • It does not require you to change your code mainly, instead it just adds a few lines.

Hope this helps :-)

0
source

As you want to find a port that is not used in your application, you can run the following command:

 netstat -tupln | awk '{print $4}' | cut -d ':' -f2 

so in your application you will use this as:

 const exec = require('child_process').exec; exec('netstat -tupln | awk '{print $4}' | cut -d ':' -f2', (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); return; } var listPorts = stdout.split(/\n/) console.log(listPorts); // list of all ports already in use var aa = _.random(50000, 65000); // generate random port var isFree = (listPorts.indexOf(aa)===-1) ? true : false; if(isFree){ //start your appliation }else{ // restart the search, write this in a function and start search again } }); 

this should provide you with a list of all ports used, so use any port except one in listPorts .

-1
source

Source: https://habr.com/ru/post/1260653/


All Articles