如果netstat另有说明,我为什么会得到" java.net.BindException:每个套接字地址只有一种用法"?
- 我使用端口9000启动使用Jetty服务器的应用程序。
- 然后,我使用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服务器之前以某种方式避免它吗?
编辑#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() );
可能与空闲时间有关吗?
编辑#2下一个难题可能无济于事:在Debug Mode(Eclipse)中运行应用程序时,服务器可以毫无问题地启动!!!但是,当在"运行模式"下或者作为内置jar文件运行应用程序时,上述问题可重复发生。威士忌探戈狐步舞?
编辑#3(4天后)仍然有问题。有什么想法吗?
解决方案
在套接字对象上调用bind()
之前,我们可能需要先调用setReuseAddress(true)
。这是由于即使关闭套接字后,TCP连接仍然存在。
我不确定Jetty,但我注意到有时候Tomcat不会在我们的某些Linux服务器上完全关闭。在这种情况下,Tomcat将重新启动,但由于先前的实例仍绑定到该端口,因此无法使用该端口。在这种情况下,我们必须找到恶意进程并在重新启动Tomcat之前明确杀死-9. 我不确定这是Java错误还是特定于Tomcat或者我们正在使用的JVM。
在程序首次调用期间,它是否接受至少一个传入连接?如果是这样,那么我们最有可能看到的是套接字停留有效。
为了获得最佳解释,请查阅由史蒂文斯(Stevens)说明的TCP / IP副本。
替代文字http://www.kohala.com/start/gifs/tcpipiv1.gif
但是,据我所知,由于应用程序未正确关闭连接(即客户端和服务器都发送了FIN / ACK序列),因此在我们认为正在断开连接之前,无法重用我们正在监听的套接字,即所谓的2MSL暂停。 1 MSL的值可能因操作系统而异,但通常至少为一分钟,通常为5.
我听到的避免这种情况的最佳建议(除了始终在退出时始终正确关闭所有套接字)是在listen()阶段将服务器套接字上的SO_LINGER tcp选项设置为0。正如自由空间指出的那样,在Java中,这是setReuseAddress(true)方法。
我必须说,我还认为这是setReuseAddress(true)解决的常见问题。但是,在这种情况下,错误消息通常是JVM无法绑定到端口的。我以前从未看过发布的错误消息。使用Google搜寻似乎暗示另一个进程正在监听一个或者多个(但不是全部)网络接口,并且我们请求进程绑定到所有接口,而它可以绑定到某些接口(另一个进程没有监听),但不是全部。只是在这里猜测...