«java.net.BindException: адрес уже используется» при попытке выполнить быстрое создание и уничтожение сокета для нагрузочного тестирования - PullRequest
26 голосов
/ 17 января 2011

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

java.net.BindException: адрес, который уже используется: connect

Согласно прочитанной мной документации, причина этого в том, что закрытые сокеты все еще занимают локальный адрес, назначенный им в течение некоторого времени после вызова close (). Это зависит от ОС, но может быть порядка минут. Я попытался вызвать setReuseAddress(true) на сокете, надеясь, что его адрес будет многократно использоваться сразу после вызова close(). К сожалению, это не так.

Мой код для создания сокета:

Socket socket = new Socket();
socket.setReuseAddress(true);
socket.connect(new InetSocketAddress(m_host, m_port));

Но я все еще получаю эту ошибку:

java.net.BindException: адрес уже используется: подключиться через некоторое время.

Есть ли другой способ выполнить то, что я пытаюсь сделать? Я хотел бы, например: открыть 100 розеток, закрыть их все, открыть 200 розеток, закрыть их все, открыть 300 и т. Д., Максимум до 2000 сокетов.

Любая помощь будет принята с благодарностью!

Ответы [ 3 ]

19 голосов
/ 17 января 2011

Вы исчерпываете пространство исходящих портов, открывая столько исходящих сокетов в течение периода TIME_WAIT в две минуты.Первый вопрос, который вы должны задать себе: это вообще реалистичный нагрузочный тест?Реальный клиент действительно собирается это сделать?Если нет, вам просто нужно пересмотреть свою методологию тестирования.

КСТАТИ SO_LINGER - это количество секунд, в течение которых приложение будет ожидать в течение close () для сброса данных.Обычно это ноль.Порт будет зависать в течение интервала TIME_WAIT в любом случае, если это конец, который дал закрытие.Это не одно и то же.Можно использовать опцию SO_LINGER для исправления проблемы.Однако это также приведет к исключительному поведению на одноранговом узле, и опять же это не является целью теста.

1 голос
/ 17 января 2011

Не использовать bind (), но setReuseAddress (true) просто странно, я надеюсь, что вы понимаете последствия setReuseAddress (и смысл). 100-2000 - это , а не большое количество открываемых сокетов, однако сервер, к которому вы пытаетесь подключиться (поскольку он выглядит как та же пара addr / port), может просто отбросить их без обычного отставания 50.

Edit: если вам нужно быстро открыть несколько сокетов (ermm port scan?), я бы очень настоятельно рекомендовал использовать NIO и connect () / finishConnect () + Selector. Открытие 1000 розеток в одной и той же нити просто медленное. Забыл, что вам может понадобиться finishConnect () в любом случае в вашем коде.

0 голосов
/ 17 января 2011

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

Попробуйте обернуть оператор connect в try/catch.

Вот некоторый псевдокод, который передает то, что, я думаю, будет работать:

portNumber = x //where x is the first port number you will try
numConnections = 200 // or however many connections you want to open
while(numConnections > 0){
    try{
        connect(host, portNumber)
        numConnections--
    }catch(){}
    portNumber++
}

Этот код не охватывает угловые случаи, такие как "что происходит, когда используются все порты?"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...