Почему я получаю «java.net.BindException: только одно использование каждого адреса сокета», если netstat говорит что-то еще? - PullRequest
2 голосов
/ 19 сентября 2008
  • Я запускаю свое приложение, которое использует сервер Jetty, используя порт 9000.
  • Затем я закрыл свое приложение с помощью Ctrl-C
  • Я проверяю с помощью "netstat -a" и вижу, что порт 9000 больше не используется.
  • Я перезапускаю свое приложение и получаю:
[ERROR,9/19 15:31:08] java.net.BindException: Only one usage of each socket address (protocol/network address/port) is normally permitted
[TRACE,9/19 15:31:08] java.net.BindException: Only one usage of each socket address (protocol/network address/port) is normally permitted
[TRACE,9/19 15:31:08]        at java.net.PlainSocketImpl.convertSocketExceptionToIOException(PlainSocketImpl.java:75)

[TRACE,9/19 15:31:08]        at sun.nio.ch.Net.bind(Net.java:101)
[TRACE,9/19 15:31:08]        at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:126)
[TRACE,9/19 15:31:08]        at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:77)
[TRACE,9/19 15:31:08]        at org.mortbay.jetty.nio.BlockingChannelConnector.open(BlockingChannelConnector.java:73)

[TRACE,9/19 15:31:08]        at org.mortbay.jetty.AbstractConnector.doStart(AbstractConnector.java:285)
[TRACE,9/19 15:31:08]        at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
[TRACE,9/19 15:31:08]        at org.mortbay.jetty.Server.doStart(Server.java:233)
[TRACE,9/19 15:31:08]        at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
[TRACE,9/19 15:31:08]        at ...

Это ошибка Java? Можно ли как-то избежать этого перед запуском сервера Jetty?

Edit # 1 Вот наш код для создания нашего BlockingChannelConnector, обратите внимание на "setReuseAddress (true)":

    connector.setReuseAddress( true );
    connector.setPort( port );
    connector.setStatsOn( true );
    connector.setMaxIdleTime( 30000 );
    connector.setLowResourceMaxIdleTime( 30000 );
    connector.setAcceptQueueSize( maxRequests );
    connector.setName( "Blocking-IO Connector, bound to host " + connector.getHost() );

Может ли это иметь какое-то отношение к простоям?

Edit # 2 Следующая часть головоломки, которая может или не может помочь: при запуске приложения в режиме отладки (Eclipse) сервер запускается без проблем !!! Но описанная выше проблема возникает воспроизводимо при запуске приложения в режиме запуска или в виде встроенного файла JAR. Виски Танго Фокстрот?

Редактировать # 3 (4 дня спустя) - проблема все еще есть. Есть мысли?

Ответы [ 4 ]

3 голосов
/ 19 сентября 2008

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

Для лучшего объяснения выкопайте копию TCP / IP, иллюстрированную Стивенсом

alt text
(источник: kohala.com )

Но, насколько я понимаю, из-за того, что приложение неправильно закрыло соединение (то есть ОБА клиент и сервер отправили свои последовательности FIN / ACK), сокет, который вы слушали, не может быть повторно использован, пока соединение не будет считаться мертвым, так называемый тайм-аут 2MSL. Значение 1 MSL может варьироваться в зависимости от операционной системы, но обычно оно составляет не менее минуты, а обычно больше 5.

Лучший совет, который я слышал, чтобы избежать этого условия (кроме того, чтобы всегда закрывать все сокеты должным образом при выходе), это установить для параметра tcp SO_LINGER значение 0 на сокете вашего сервера во время фазы listen (). Как указано в свободном пространстве, в Java это метод setReuseAddress (true).

1 голос
/ 19 сентября 2008

Возможно, вы захотите вызвать setReuseAddress(true) перед вызовом bind() для вашего объекта сокета. Это вызвано сохранением соединения TCP даже после закрытия сокета.

0 голосов
/ 20 сентября 2008

Должен сказать, я также подумал, что это обычная проблема, решаемая setReuseAddress (true). Однако сообщение об ошибке в этом случае обычно является чем-то вроде того, что JVM не может привязать к порту. Я никогда не видел опубликованное сообщение об ошибке раньше. Похоже, что поиск в Google предполагает, что другой процесс прослушивает один или несколько (но не все) сетевых интерфейсов, и вы запрашиваете, чтобы ваш процесс связывался со всеми интерфейсами, тогда как он может связываться с некоторыми (теми, которые другой процесс не слушает). к) но не все из них. Просто думаю, что здесь ...

0 голосов
/ 19 сентября 2008

Я не уверен насчет Jetty, но заметил, что иногда Tomcat не завершает свою работу на некоторых наших серверах Linux. В таких случаях Tomcat перезапустится, но не сможет использовать соответствующий порт, поскольку предыдущий экземпляр все еще привязан к нему. В таких случаях мы должны найти мошеннический процесс и явно убить -9, прежде чем перезапустить Tomcat. Я не уверен, является ли это ошибкой Java или специфической для Tomcat или JVM, которую мы используем.

...