Подтвердить что ты не робот

"java.net.BindException: адрес уже используется" при попытке быстрого создания и уничтожения Socket для тестирования нагрузки

Я пытаюсь загрузить тестовый сервер 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.

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

4b9b3361

Ответ 1

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

BTW SO_LINGER - это количество секунд, которое приложение будет ждать во время закрытия() для сброса данных. Обычно он равен нулю. В любом случае, порт будет находиться в интервале TIME_WAIT, если это конец, который выдает закрытие. Это не одно и то же. Можно использовать опцию SO_LINGER для исправления проблемы. Однако это также вызовет исключительное поведение у сверстника, и снова это не является целью теста.

Ответ 2

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

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

Ответ 3

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

Попробуйте обернуть оператор 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++
}

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