DatagramChannel.close()在Windows上保持端口打开

我正在实施一个Discover流程:

  • 打开UDP套接字以侦听给定端口上的广播响应
  • 发送一些请求(并期待以后的响应)
  • 在给定的时间段后关闭UDP套接字

第一个电话有效。 但是其他调用会出现绑定错误。 已经在使用的地址:bind

我正在运行Windows 7.我做了一些测试,发现在channel.close()之后; Netstat仍然给出:

netstat -a -b -sp udp | grep 55224

UDP 0.0.0.0:55224

所以udp端口仍然在操作系统级别打开

我搜索了网络,它可能是os级别的泄漏: 一些java数据报套接字问题

我使用NIO通道运行了2次测试,没有使用1次(来自网络上的测试)。 我使用NIO版本重现了我的错误,但如果我不使用NIO,它会有效。

我有人可以指出我如何使它适用于NIO。 目标平台是Android,我不想总是听广播但只是重复一段时间。

测试sockets

  public void testConnectCloseWithSocket() { long tCumulative = 0; int errAt = -1; System.out.println("start..."); for (int i = 0; i < 4000; i++) { try { errAt = i; DatagramSocket result = new DatagramSocket(null); result.bind(new InetSocketAddress(InetAddress.getLocalHost(), 9005)); result.close(); //success at last tCumulative = 0; } catch (Exception e) { System.out.println("Error (at="+errAt+") (waited="+tCumulative+"ms): " + e.getMessage()); tCumulative+=50; try { Thread.sleep(50); } catch (InterruptedException e1) { } i--; } } System.out.println("end..."); } 

RESULT SOCKET <

start …错误(at = 1319)(等待= 0ms):地址已在使用中:无法绑定

错误(at = 1438)(等待= 0ms):地址已在使用中:无法绑定

错误(at = 1587)(等待= 0ms):地址已在使用中:无法绑定

错误(at = 1740)(等待= 0ms):地址已在使用中:无法绑定

结束…


我确实得到了一些错误,但套接字正确关闭…这是我需要的oki

通道测试

  public void testConnectCloseWithChannel() { long tCumulative = 0; int errAt = -1; System.out.println("start..."); for (int i = 0; i < 4000; i++) { try { errAt = i; Selector selector = Selector.open(); DatagramChannel channel = DatagramChannel.open(); channel.configureBlocking(true); channel.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 9005)); SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ); clientKey.cancel(); channel.close(); //success at last tCumulative = 0; } catch (Exception e) { System.out.println("Error (at="+errAt+") (waited="+tCumulative+"ms): " + e.getMessage()); tCumulative+=50; try { Thread.sleep(tCumulative); } catch (InterruptedException e1) { } i--; } } System.out.println("end..."); } 

注意:channel.register注释测试工作..


结果与渠道

start …错误(at = 0)(等待= 0ms):null错误(at = 0)(等待= 50ms):地址已在使用中:bind

错误(at = 0)(等待= 100ms):地址已在使用中:bind

错误(at = 0)(等待= 150ms):地址已在使用中:bind …


谢谢你的帮助

我确实得到了一些错误,但套接字正确关闭…这是我需要的oki

不,如果您有错误,您的频道未正确关闭。

您必须在try块的finally子句中close

 Selector selector = Selector.open(); try { DatagramChannel channel = DatagramChannel.open(); try { channel.configureBlocking(true); channel.socket().bind( new InetSocketAddress(InetAddress.getLocalHost(), 9005) ); SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ); clientKey.cancel(); } finally { channel.close(); } } finally { selector.close( ) } 

如果通道使用选择器注册,则通道关闭的某些部分将延迟到下一个select()。 它记录在Selector,AbstractSelector,SelectorSpi,SelectableChannel,AbstractSelectableChannel的森林中的某个地方,在我需要的时候我永远找不到它。 如果您在关闭频道时处于选择循环和线程内,则可以通过调用selectNow()立即使其立即进行。