Ошибка привязки сокета

У меня есть тестовое приложение, которое открывает сокет, отправляет что-то через этот сокет, а затем закрывает его. Это делается в цикле 5-10 000 раз. Дело в том, что после 3400 итераций я получаю ошибку такого типа:

java.net.BindException: Address already in use: connect

Я даже установил сокет для немедленного использования, но ошибка сохраняется

try
{
     out_server.write(m.ToByteArray());
     socket_server.setReuseAddress(true);
     socket_server.close();
}
catch(Exception e)
{
     e.printStackTrace();
     System.out.println(i+" unable to register with the server");
}

Что я мог сделать, чтобы это исправить?

Ответы на вопрос(7)

что у вас заканчиваются конечные точки сокетов. Однако это не на 100% кристально ясно из вашего примера, поскольку, вероятно, исключение исходит от вызова connect () или bind (), который может лежать в основе какого-то другого высокоуровневого метода Java.

One также должен подчеркнуть, что нехватка конечных точек - это не какое-то странное ограничение библиотеки сокетов, а довольно фундаментальная часть любой реализации TCP / IP. Вам необходимо некоторое время хранить информацию о старых соединениях, чтобы опоздавшие IP-пакеты для старого соединения отбрасывались.

setReuseAddress () соответствует низкоуровневой опции сокета SO_REUSEADDR и применяется только к серверу, когда он выполняет listen ().

 Aditya Sehgal06 июл. 2009 г., 10:29
Неправильно, что опция сокета SO_REUSEADDR предназначена только для сервера. Эта опция может использоваться как серверами, так и клиентами.

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

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

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

Я думаю, это то, что происходит в вашем случае, сокеты освобождаются не так быстро, как вы думаете.

У нас была похожая проблема с кодом, который открывал множество недолговечных сессий. Некоторое время он работал нормально, но затем аппаратная часть работала быстрее, что позволяло открывать еще больше за определенный период времени. Это проявилось в невозможности открыть больше сессий.

Один из способов проверить это - сделатьnetstat -a из командной строки и посмотрите, сколько сессий фактически находится в состоянии ожидания.

Если это действительно так, то есть несколько способов справиться с этим.

повторно использовать ваши сеансы, либо вручную, либо поддерживая пул соединений. введите задержку в каждом соединении, чтобы попытаться остановить достижение точки насыщения. уходите, пока не достигнете насыщения итогд измените свое поведение, например, запустите логику соединения внутри оператора while, который повторяется до 60 раз с задержкой в две секунды каждый раз, прежде чем полностью отказаться. Это позволяет работать на полной скорости, замедляя работу только в случае возникновения проблемы.

Последний пункт заслуживает некоторого расширения. Мы фактически использовали стратегию отсрочки в нашем вышеупомянутом приложении, которое постепенно уменьшало бы нагрузку на поставщика ресурсов, если бы оно жаловалось, поэтому вместо 30 двухсекундных задержек мы выбрали одну секунду, затем две секунды. затем четыре и так далее.

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

set maxdelay to 16 # maximum time period between attempts
set maxtries to 10 # maximum attempts

set delay to 0
set tries to 0
while more actions needed:
    if delay is not 0:
        sleep delay
    attempt action
    if action failed:
        add 1 to tries
        if tries is greater than maxtries:
           exit with permanent error
        if delay is 0:
            set delay to 1
        else:
            double delay
            if delay is greater than maxdelay:
                set delay to maxdelay
    else:
        set delay to 0
        set tries to 0

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

 Ryan Fernandes06 июл. 2009 г., 08:37
вам придется настроить сокет time_wait и другие связанные параметры в зависимости от ОС (компьютера, к которому вы подключаетесь)
 paxdiablo06 июл. 2009 г., 08:40
Не всегда стоит возиться с этими параметрами. Большинство должно быть настроено на характеристики сети, а затем ваше приложение должно быть настроено для этого. Уменьшение времени ожидания без уменьшения времени жизни приведет к появлению ложных пакетов. Снижение TTL до точки, в которой пакеты не могут достичь пункта назначения, означает большое количество отброшенных пакетов. В идеале вы должны либо держать соединения открытыми (вручную или с помощью пула соединений), либо настраивать поведение своих приложений (например, с задержкой, упомянутой @Stu в своем ответе).

и я предполагаю, что вы используете, то есть ограничение на количество клиентских подключений, которые вы можете иметь (это настраивается с помощьюMaxUserPort запись реестра, которая по умолчанию равна 4000; видетьhttp: //technet.microsoft.com/en-us/library/aa995661.asp а такжеhttp: //www.tech-archive.net/Archive/Windows/microsoft.public.windows.server.general/2008-09/msg00611.htm для деталей об изменении этого). Это в сочетании с тем фактом, что вы запускаете сокет близко от своего клиента и таким образом накапливаете сокеты вTIME_WAIT состояние вашего клиента, вероятно, является причиной вашей проблемы.

Обратите внимание, что решениеTIME_WAITроблема накопления не в том, чтобы возиться с параметрами стека TCP, чтобы проблема исчезла.TIME_WAIT существует по очень веской причине, и удаление или сокращение его, вероятно, вызовет у вас новые проблемы!

Итак, если вы на компьютере с Windows, первый шаг - это настроитьMaxUserPortначение @, чтобы у вас было больше динамических портов для исходящих соединений. Затем, если это не решит проблему, вы можете подумать о том, какая сторона соединения должна заканчиваться символом TIME_WAIT (при условии, что вы можете контролировать протокол, используемый в ваших соединениях ...) Пир, который выдает «активное закрытие», - это тот, который заканчивается символомTIME_WAIT так что если вы можете что-то изменить, чтобы ваши серверы выдавали активное закрытие, тоTIME_WAIT сокеты будут накапливаться на сервере, а не на клиенте, и этоМОЖЕ будет лучше для тебя ...

 Will Angley27 мая 2014 г., 21:30
Обратите внимание, что это работает только на клиентах Windows через XP и серверах до 2003 года. Vista и Server 2008 и выше используют новую реализацию TCP / IP, и вам нужно использоватьnetsh interface ipv4 show dynamicportrange tcp, чтобы показать, и соответствующийset команда, чтобы изменить эти значения. Компьютер под управлением Windows 7 Enterprise, который мне приходилось иметь, имеет по умолчанию 16384 динамических порта, что в значительной степени снимает это ограничение.
 klaus johan06 июл. 2009 г., 18:26
На самом деле я использую Windows Xp. Я не знаю, какой предел для входящих подключений, но если он такой же, как исходящие подключения, то я просто перенесу проблему на сервер. Тем не менее, я думаю, что максимизация исходящих портов - это хороший подход. Благодарность
 Len Holgate06 июл. 2009 г., 19:52
Нет никаких ограничений на входящие соединения.

вать сокет, и цикл будет выполняться (в цикле он будет пытаться установить соединение с сокетом с тем же ip и портом) намного быстрее, поэтому, пожалуйста, обнулите сокет.

Socket_server.close ();

socket_server = null;

Спасибо Сунил Кумар Саху

как вы выполняете цикл, возможно, вы ошиблись.

Thejava docs для setReuseAddress говорят: поведение, когда SO_REUSEADDR включен или отключен после привязки сокета (см. isBound ()), не определено.

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

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

Java Bind Exception

промойте сокет после записи добавить немного сна (~ 50 мс?) в конце описанного выше метода

@ Pax имеет хорошее представление о состоянии сокета после этого. Попробуйте свой код, дайте ему потерпеть неудачу, а затем сделайтеnetstat и проанализируй (или опубликуй здесь)

 klaus johan06 июл. 2009 г., 08:48
На самом деле у меня было время сна, но оно длилось всего 5 мс.

Ваш ответ на вопрос