【问题标题】:DatagramChannel.close() keeps port open on WindowsDatagramChannel.close() 在 Windows 上保持端口打开
【发布时间】:2012-10-24 12:33:31
【问题描述】:

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

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

第一个电话有效。但其他调用得到一个绑定错误。地址已在使用中:绑定

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

netstat -a -b -sp udp | grep 55224

UDP 0.0.0.0:55224 :

所以 udp 端口​​还是在 OS 级别打开的

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

我运行了 2 个测试,一个使用 NIO 通道,一个不使用(来自网络上的测试)。我用 NIO 版本重现了我的错误,但如果我不使用 NIO,它就可以工作。

任何人都可以指出我如何使它与 NIO 一起工作。目标平台是 Android,我不t want 始终收听广播,但只收听重复的时间段。

测试插座

    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...");

}

结果套接字

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

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

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

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

结束...


我确实遇到了一些错误,但是套接字被正确关闭了……这对我的需要来说是可以的

使用通道测试

    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):空 错误(at=0)(等待=50ms):地址已在使用:绑定

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

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


感谢您的帮助

【问题讨论】:

    标签: java udp nio


    【解决方案1】:

    我确实遇到了一些错误,但套接字正确关闭了...... 可以满足我的需要

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

    您必须在 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( )
    }
    

    【讨论】:

    • 感谢您的注意,在处理您的代码时,我注意到我没有关闭选择器。关闭它一切正常 :-) 谢谢!
    • @DavidGagnon 那是因为我的回答中提出的问题。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2014-06-25
      • 1970-01-01
      • 1970-01-01
      • 2015-06-28
      • 1970-01-01
      • 2021-04-29
      • 1970-01-01
      • 2013-10-19
      • 1970-01-01
      相关资源
      最近更新 更多