为什么我得到“java.net.BindException:每个套接字地址只有一个用法”如果netstat说了别的话?

问题描述 投票:2回答:4
  • 我使用端口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下一个可能有帮助或可能没有帮助的部分:在调试模式(Eclipse)中运行应用程序时,服务器启动时没有问题!但是,当在运行模式下运行应用程序或作为构建的jar文件时,上述问题可重现。 Whiskey Tango Foxtrot?

编辑#3(4天后) - 仍有问题。有什么想法吗?

java sockets jetty
4个回答
3
投票

在您第一次调用程序时,它是否接受至少一个传入连接?如果是这样,那么你最有可能看到的是套接字停留有效。

为了获得最佳解释,请编写一份由Stevens撰写的TCP / IP Illustrated副本

alt text (来源:kohala.com

但是,据我所知,因为应用程序没有正确关闭连接(即客户端和服务器发送了它们的FIN / ACK序列),所以在连接被认为死亡之前,无法重用您正在侦听的套接字,即所谓的2MSL超时。 1 MSL的值可能因操作系统而异,但通常至少一分钟,通常更像是5。

我听到的避免这种情况的最佳建议(除了在退出时始终正确关闭所有套接字)是在listen()阶段将SO_LINGER tcp选项设置为服务器套接字上的0。正如freespace指出的那样,在java中这是setReuseAddress(true)方法。


1
投票

您可能需要在调用socket对象上的setReuseAddress(true)之前调用bind()。这是由于TCP连接在套接字关闭后仍然存在。


0
投票

我不确定Jetty,但我注意到有时Tomcat不会在我们的某些Linux服务器上干净地关闭。在这种情况下,Tomcat将重新启动但无法使用有问题的端口,因为前一个实例仍然绑定到它。在这种情况下,我们必须找到流氓进程并在重新启动Tomcat之前显式地杀死它。我不确定这是一个java bug还是特定于Tomcat或我们正在使用的JVM。


0
投票

我必须说我也认为这是setReuseAddress(true)解决的常见问题。但是,在这种情况下的错误消息通常是JVM无法绑定到端口的行。我以前从未见过发布的错误消息。谷歌搜索它似乎表明另一个进程正在侦听一个或多个(但不是全部)网络接口,并且您请求您的进程绑定到所有接口,而它可以绑定到某些(其他进程不监听的进程) to)但不是全部。只是在这里猜测......

© www.soinside.com 2019 - 2024. All rights reserved.