find免费的端口不用于应用程序 – find一些algorithm

我在我的程序中使用以下API来设置自由端口并将其提供给应用程序运行

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

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

这个自由端口被给予应用程序使用和工作正常。 问题是,如果我给application A提供一个自由端口,并且应用程序还没有占用它(有时需要一些时间…),并且有其他application B请求一个空闲端口,所以它给APP B应用程序的端口A导致问题…是否有任何优雅的方式来解决它?

我的应用程序没有状态,所以它不能保存到哪个应用程序获取哪个端口…

有解决scheme,我们可以随机的范围,但这是不健壮的…

在我的应用程序中获取我应该提供免费的端口运行的应用程序的URL。

更新

不能使用一些经纪人或别的什么东西可以控制这个外面我需要find一些algorithm (也许有一些聪明的随机),可以帮助我在内部做,即我的程序是像单身人士,我需要一些技巧,如何给端口50000 to 65000 ,这将减less提供给应用程序的端口的冲突量

更新2

我决定尝试下面这样的事情,你觉得怎么样?

使用lodash https://lodash.com/docs/4.17.2#random来确定提供3(或更多,如果有意义的话)数字的循环之间的端口,如下面的范围

 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); 

那么如果我在端口被误认为全部3个端口都被占用了,那么再次运行这个程序为另外3个随机的number.commentsbuild议是欢迎的! 我试图find一些方法尽可能地避免碰撞

如果您的应用程序可以使用SO_REUSEADDR等选项打开端口,但是操作系统会将端口保持在TIME_WAIT状态,您可以使用SO_REUSEADDR绑定/打开希望返回的端口,并立即closures并将其返回给应用程序。 因此,在TIME_WAIT期间(视操作系统而定,可以是30秒,实际时间应该被决定/设置或者通过实验/pipe理发现),端口列表将显示该端口被占用。

如果您的端口search器没有为TIME_WAIT状态的端口提供端口号,那么通过相对昂贵的开/关套接字操作解决了问题。

我build议你找一个保持状态的方法。 即使是暂时的状态,在记忆中,总比什么都没有好。 这样你至less可以避免给你已经发出的端口。 因为这些很可能不再是免费的。 (如果你发现你已经发现了一个随机的端口,这将会像保存它们一样简单,并且重新生成一个随机的端口)。 如果你不想碰撞,build立你的模块有状态,这样可以避免它们。 如果你不想这样做,你将不得不接受在不需要的时候有时会碰撞。

如果你得到的URL是随机的,你可以做的最好的是随机猜测。 如果你可以得到一些独特和一致的URL的属性,你可以devise一些东西。

代码示例:

 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; } 

笔记:

  • checkPortInUse可能会是asynchronous的,所以你必须适应。
  • 你说'50000到65000'之间。 这是从50000到65000。

你有没有尝试过这样的事情?

 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); }, } }; 

我只是简单地接受这样一个事实,即在分布式系统中事情可能会出错,如果在第一次尝试中出于任何原因失败,则重试操作(即,获得自由端口)。

幸运的是,有很多npm模块已经为你做了,例如重试 。

使用此模块,您可以重试asynchronous操作,直到成功为止,并configuration等待策略以及最多重试多less次,依此类推…

为了提供一个代码示例,它基本上归结为诸如:

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

这个解决scheme的好处是:

  • 没有locking的工作,即它是有效的,如果一切正常,使资源使用率低。
  • 没有中央经纪人或类似的东西。
  • 适用于任何规模的分布式系统。
  • 使用可以在分布式系统中重用的模式来解决各种问题。
  • 所有这些事情都使用经过战斗testing和坚实的NPM模块,而不是手写。
  • 不要求您主要更改代码,而只需添加几行即可。

希望这可以帮助 :-)

当pipe理多个应用程序或多个服务器时,第一次必须正确(无需重试),您需要一个真实的来源。 只要资源是“可locking的”,同一台计算机上的应用程序就可以与数据库,代理服务器甚至文件进行通信。 (服务器以类似的方式工作,但不是用本地文件)。

所以你的stream量会是这样的:

  1. 应用程序A向服务发送请求以请求locking。
  2. locking确认后,启动端口扫描器
  3. 当使用端口时,释放locking。

同样,这可能是你写的一个“PortService”,它提供了未使用的端口,或者是在一些共享资源上的一个简单的锁,所以有两件事同时得到同一个端口。

希望你能find适合你的应用程序的东西。

当你想find一个在你的应用程序中没有被使用的端口时,你可以做的是运行下面的命令:

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

所以在你的应用程序中,你将使用这样的:

 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 } }); 

这应该给你列出所有正在使用的端口,所以使用除了listPorts中的端口之外的任何端口。