我经常遇到一个奇怪的问题(实际上经常发生)。
我正在运行一个服务器应用程序,它正在为自己绑定一个套接字。
但有一段时间,套接字没有被释放。虽然Eclipse报告Terminate失败,但是它会从'ps'和JConsole / JVisualVM中正确消失,但是该过程终止了。 'lsof'也不再为港口显示任何内容。但是,当我尝试再次将服务器启动到同一端口时,我收到此错误:
Caused by: java.net.BindException: Address already in use
at sun.nio.ch.Net.bind(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:126)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
我的单元测试中的问题是最糟糕的,它从未完全运行,因为这肯定会在其中一个测试之后发生(所有测试都会重新创建服务器)。
我正在运行MacOSX 10.7.3
Java(TM)SE运行时环境(版本1.6.0_31-b04-415-11M3635) Java HotSpot(TM)64位服务器VM(版本20.6-b01-415,混合模式)
我也有Parallels,而且问题看起来似乎是由Parallels网络适配器引起的,但我不确定它是否与此问题有任何关系(我已经联系了他们的支持,目前为止没有任何帮助)
唯一有助于解决此问题的方法是重启OSX。
有什么想法吗?
-
这是打开套接字的相关代码:
channel = (ServerSocketChannel) ServerSocketChannel.open().configureBlocking(false);
channel.socket().bind( addr, 0 );
并由
关闭 channel.close();
但我认为这个过程在这里被卡住了,然后Eclipse就会杀死它。
-
netstat -an(对于端口6007):
tcp4 73 0 127.0.0.1.6007 127.0.0.1.51549 ESTABLISHED
tcp4 0 0 127.0.0.1.51549 127.0.0.1.6007 ESTABLISHED
tcp4 73 0 127.0.0.1.6007 127.0.0.1.51544 CLOSE_WAIT
tcp4 0 0 127.0.0.1.6007 127.0.0.1.51543 CLOSE_WAIT
tcp4 0 0 10.37.129.2.6007 *.* LISTEN
tcp4 0 0 10.211.55.2.6007 *.* LISTEN
tcp4 0 0 127.0.0.1.6007 *.* LISTEN
tcp4 0 0 10.50.100.236.6007 *.* LISTEN
-
现在我在为每个测试打开套接字后得到此异常(此情况下的netstat输出):
Caused by: java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.net.SocketInputStream.read(SocketInputStream.java:182)
-
从eclipse停止进程我得到“终止失败”,但是lsof -i TCP:6007什么也没显示,'ps'找不到进程。 netstat输出没有改变......
我可以以某种方式在没有重启的情况下杀死套接字(这会有点帮助吗?)
-
更新5.5.12:
我现在在Eclipse调试器中运行测试。这次测试在18种方法后被卡住了。它被困在15分钟后停止了主线程。这是堆栈:
Thread [main] (Suspended)
FileDispatcher.preClose0(FileDescriptor) line: not available [native method]
SocketDispatcher.preClose(FileDescriptor) line: 41
ServerSocketChannelImpl.implCloseSelectableChannel() line: 208 [local variables unavailable]
ServerSocketChannelImpl(AbstractSelectableChannel).implCloseChannel() line: 201
ServerSocketChannelImpl(AbstractInterruptibleChannel).close() line: 97
...
-
嗯,毕竟看起来这个过程并没有被杀死 - 并且也不会死于杀死-9(我注意到过程712,可能还有710是TestNG进程):
$ kill -9 712
$ ps xa | grep java
700 ?? ?E 0:00.00 (java)
712 ?? ?E 0:00.00 (java)
797 s005 S+ 0:00.00 grep java
- 编辑:10.5.12:
?上面ps输出中的E表示进程正在退出。我找不到任何方法可以在不重新启动的情况下完全杀死这样一个进程。其他一些应用程序也注意到了同样的问题。找不到解决方案:
答案 0 :(得分:3)
尝试关闭套接字 http://docs.oracle.com/javase/1.4.2/docs/api/java/net/ServerSocket.html#close() 每次测试后,在拆解时,如果你还没有。
答案 1 :(得分:3)
这里只是一个黑暗的镜头,但要确保等待Selector.select()的任何线程已经被唤醒,并且已经退出。
答案 2 :(得分:2)
所以似乎问题在于JDK 6的Mac版本中Selector的实现。安装新的Oracle JDK 7u4修复了这个问题,与使用Selector的方式无关。
答案 3 :(得分:0)
我也有Parallels,而且问题通常是由Parallels网络适配器引起的......
如果这个问题没有在其他平台上出现,我会说这是一个公平的赌注。你有什么办法将Parallels排除在罪魁祸首之外?
答案 4 :(得分:0)
如果您认为资源未正确发布,您可以尝试在shutdownhook中执行发布。这样至少当它关闭时,资源将会被释放(不过如果你难以杀死)
一个非常基本的shutdownhook示例:
public void shutDownProceedure(){
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
/* my shutdown code here */
}
});
}
这帮助我释放了之前未完全发布的资源。我不知道这是否也适用于套接字,我认为应该这样做。
它还让我看到了之前没见过的记录