2016-12-01 2 views
5

я использую следующий API в моей программе detrmine свободный порт и предоставить его приложения для запускаНайти свободный порт не используется для приложений - найти алгоритм

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 Какая причина для проблемы ... Есть ли какой-нибудь элегантный способ решить эту проблему?

мое приложение не имеет состояния, поэтому он не может сохранить какие приложения получить какой порт ...

Существует решение, что мы можем рандомизации диапазон, но это не надежный ...

В мое приложение Im получает URL-адрес приложения, который должен предоставить свободный порт для запуска.

обновление

Я не могу использовать некоторые брокера или коснуться еще, что проверочные это снаружи, мне нужно найти какой-то алгоритм (возможно, с некоторыми смарт случайными), которые могут помочь мне сделать это внутренне т.е. моя программа как синглтон и мне нужно немного трюк, как дать порт между 50000 to 65000 который будет уменьшить количество столкновений порта, который был предоставлен для приложений

update 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 других случайных предложений номер.com приветствуются !!! Я пытаюсь найти какой-то способ, чтобы избежать столкновений, насколько это возможно ...

+0

держать порт приложение А открывается до тех пор, как приложение А не открыть его сам по себе. Или используйте брокерское обслуживание для более безопасного назначения порта. –

+0

@ mh-cbon - 1. как вы можете привести пример? 2. если я изменил его, чтобы открыть, когда приложение A хочет его использовать, не будет ошибок/проблем? –

+2

@RaynD, есть ли какая-то особая причина не позволять ОС назначать случайный номер порта во время вызова 'listen()' и порта отчета именно тогда? –

ответ

0

При работе с несколькими приложениями или несколько серверами, на которых один должна быть прямо в первый раз (без повтора), вам нужен единый источник правда. Приложения на одном компьютере могут разговаривать с базой данных, сервером брокера или даже с файлом, если ресурс «заблокирован». (Серверы работают аналогичным образом, хотя и не с локальными файлами).

Таким образом, ваш поток будет что-то вроде:

  1. App А посылает запрос на обслуживание, чтобы запросить блокировку.
  2. Когда блокировка подтверждена, сканер портов порта
  3. Когда используется порт, отпустите фиксатор.

Опять же, это может быть «PortService», который вы пишете, чтобы раздавать неиспользуемые порты или просто блокировать в каком-то общем ресурсе, поэтому две вещи получают один и тот же порт одновременно.

Надеюсь, вы сможете найти что-то подходящее для работы в ваших приложениях.

+0

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

+0

Что вы подразумеваете под «внутренним»? Являются ли эти приложения на одной машине? Из того, что я понимаю по вашему вопросу, им нужен способ как-то координировать. – clay

+0

Я имею в виду, что я не могу использовать брокера и т. Д. Я моя программа singleton, и мне нужен какой-то алгоритм, который может уменьшить количество конфликтов, см. Мое обновление ... –

-1

Как вы хотите, чтобы найти порт, который не используется в вашем приложении, вы можете сделать, это выполнить следующую команду:

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.

+0

Спасибо за ответ, но не знаете, как это мне помогает, так как API (portscanner.findAPortNotInUse ...), который я использую, я думаю, уже сделал это внутри ... может быть, я скучаю по тебе, не могли бы вы уточнить? –

+0

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

+0

, поэтому я предполагаю, что когда вы создадите случайный порт, вы можете просто проверить список, если он существует, если он игнорирует, если не используется. Разве это не то, что вы ищете? – AJS

0

Я бы посоветовал вам искать способ сохранить состояние. Даже временное состояние, в памяти, лучше, чем ничего. Таким образом, вы могли бы, по крайней мере, избегать выдачи портов, которые вы уже выдали. Потому что они скорее всего не свободны. (Это было бы так же просто, как сохранить их и восстановить случайный порт, если вы заметили, что обнаружили случайный порт, который вы уже выдали). Если вы не хотите коллизий, создайте свой модуль, чтобы его можно было сохранить, чтобы он мог их избежать. Если вы не хотите этого делать, вам придется принять, что иногда возникают столкновения, когда их не должно быть.

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

Пример кода:

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, вероятно, будет асинхронным, так что вам придется приспособить для этого.
  • Вы сказали «между 50000 и 65000». Это от 50000 до 65000. включительно
+0

HI Alex, я думаю, что случайное семя может быть вариантом, можете ли вы представить пример кода, как мне его использовать с кодом в моем сообщении ... portscanner.findAPortNotInUse (50000, 65000, ... –

+0

Я предполагаю, что это должен каждый раз давать другой диапазон между 50000 - 65000 и пытаться найти свободный порт там, если да, если он не повторится с разным диапазоном. Как это звучит? любая идея, как использовать случайное семя с ним? –

+0

@RaynD добавил пример кода.Я должен отметить, что, опять же, с разделяемым состоянием предпочтительнее. Надеюсь, это поможет! – AlexTes

0

Если ваши приложения могут открывать порты с возможностью как SO_REUSEADDR, но операционная система поддерживает порты в списке в TIME_WAIT состоянии, вы можете связать/открыть порт, который вы хотите, чтобы вернуться с SO_REUSEADDR, немедленно закройте его и верните в приложение. Таким образом, для периода TIME_WAIT (в зависимости от операционной системы это может быть 30 секунд, и фактическое время должно быть определено/установлено или найдено экспериментом/администрированием). Список портов покажет этот порт как занятый.

Если ваш порт искатель не указывает номера портов для портов в состоянии TIME_WAIT, проблема решена относительно дорогостоящей операцией открытия/закрытия гнезда.

+0

Спасибо, но не уверен, что я получил, как его реализовать ... можете ли вы представить пример кода? –

+0

https://nodejs.org/api/net.html#net_server_listen_port_hostname_backlog_callback –

0

Вы пробовали что-то вроде этого?

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

Я бы просто принять тот факт, что все может пойти не так в распределенной системе и повторить операцию (то есть, получая свободный порт), если это не удалось по какой-либо причине на первую попытку.

К счастью, есть много модулей npm, которые делают это уже для вас, например. retry.

С помощью этого модуля вы можете повторить асинхронную операцию, пока не завершится успешно, и настраивать стратегии ожидания, и сколько раз он должен быть повторен максимально, и так далее ...

Чтобы предоставить пример кода, он в основном сводится к чему-то, такие как:

const operation = retry.operation(); 

operation.attempt(currentAttempt => { 
    findAnUnusedPortAndUseIt(err => { 
    if (operation.retry(err)) { 
     return; 
    } 

    callback(err ? operation.mainError() : null); 
    }); 
}); 

преимущества этого решения являются:

  • Работает без блокировки, т.е. является эффективным и делает низкий уровень использования ресурсов, если все в порядке.
  • Работает без центрального брокера или что-то в этом роде.
  • Работы для распределенных систем любого размера.
  • Использует шаблон, который вы можете повторно использовать в распределенных системах для всех видов проблем.
  • Использует проверенный временем и надежный модуль npm вместо почерка все эти вещи.
  • Не требует, чтобы вы меняли свой код основным способом, вместо этого он просто добавлял несколько строк.

Надеется, что это помогает :-)