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

时间:2012-10-19 15:08:53

标签: java udp nio

我正在实施一个发现过程:

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

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

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

netstat -a -b -sp udp | grep 55224

UDP 0.0.0.0:55224

因此udp端口仍然在操作系统级别打开

我搜索了网络,可能是在操作系统级别泄漏:Some java Datagram Socket questions

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

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

TEST SOCKET

    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&lt;

...开始 错误(at = 1319)(等待= 0ms):地址已被使用:无法绑定

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

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

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

...端


我确实遇到了一些错误,但套接字正确关闭了......这是我的需求

使用CHANNEL进行测试

    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注释测试工作..


结果通道

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

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

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


感谢您的帮助

2 个答案:

答案 0 :(得分:3)

  

我确实遇到了一些错误,但套接字正确关闭......这是   oki满足我的需求

不,如果你有错误,你的频道没有正确关闭。

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

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( )
}

答案 1 :(得分:0)

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