【问题标题】:Port still use after DatagramSocket is closedDatagramSocket 关闭后端口仍在使用
【发布时间】:2011-12-29 04:08:23
【问题描述】:

以下代码可以重现该问题: int errAt = -1;

  try {
    System.out.println("start...");
    for (int i = 0; i < 4000; i++) {
      errAt = i;
      DatagramSocket result = new DatagramSocket(null);
      result.bind(new InetSocketAddress(InetAddress.getLocalHost(), 9005));
      result.close();
      //System.out.println(i);
    }

  } catch (Exception e) {
    System.out.println("Error: " + e.getMessage());
    System.out.println("ErrAt: " + errAt);
    e.printStackTrace();
  } finally {
    System.out.println("end...");
  }

在我的电脑上,运行 2k+ 次后,我会看到“java.net.BindException:地址已在使用:无法绑定”异常。

我不确定,这是否意味着close方法没有立即关闭本机套接字?

【问题讨论】:

    标签: java sockets udp


    【解决方案1】:

    即使我将它设置为运行 40,000 次迭代,此代码也可以在我的 Mac 上运行。我认为这里可能的问题是套接字没有在 Windows 上立即关闭,但是您再次尝试在可能的毫秒空间内进行数千次迭代。

    以下代码将不断重试并休眠一小段时间,让您查看是否是延迟问题,即套接字会在一段时间内关闭:

        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;
                Thread.sleep(50);
                i--;
            }
        }
        System.out.println("end...");
    

    【讨论】:

    • 确实没有在 Windows 上立即关闭套接字。
    • 鉴于您可以在代码失败之前运行大约 2000 次代码,最有可能的问题是关闭和重新绑定是一种竞争条件(即 Windows 执行得非常快,但在 2000 次之后您遇到了在关闭之前尝试重新绑定的情况)或者您的 Windows 资源不足,因为它没有足够快地清除它们。您是否发现,当它失败时,它会等待一小段时间,然后在失败之前或之后为另一吨套接字工作正常,是否似乎必须等待一段时间才能关闭每个套接字?
    • 我问上述问题的原因是因为如果它似乎在大约 2000 个套接字后失败,但在您等待 50 毫秒后又可以为另外 2000 个左右的套接字工作,那么它可能只是一个竞争条件。相反,如果它在 2000 个套接字之后失败,并且您发现您可能被限制为每隔几百毫秒或秒关闭和重新绑定一个套接字,那么这表明 Windows 仅在超时后才清理资源。如果它的第一个没问题 - 你只需要等待+重试如果它发生,如果第二个你可能想要查找有关套接字清理的注册表设置。
    【解决方案2】:

    不清楚您要做什么,但解决 UDP 端口仍在使用中的问题的一种方法是在绑定之前设置“重用地址”选项。

    参考:How to set reuse address option for a datagram socket in java code?

    【讨论】:

      【解决方案3】:

      如果你创建了套接字,然后得到例如一个 BindException 你没有关闭套接字。它应该在 finally {} 块中关闭。

      很难看出这个测试的意义。普通的 UDP 程序打开 一个 DatagramSocket 并在整个进程的生命周期内保持打开状态。任何理智的程序都不会通过数千个 UDP 套接字。

      【讨论】:

      • @SunilKumarSahoo 请自行查看代码。如果 bind() 调用抛出异常,则套接字关闭。
      • @downvoters 请解释一下,除非您希望它被视为纯粹的网站破坏行为。
      • @SuniKumarSahoo EJP 答案可能不是您问题的根本原因,但它是合法的可能根本原因。将 try-with-resource 添加到 Java 的全部原因是帮助人们正确使用诸如套接字之类的可关闭资源。请参阅docs.oracle.com/javase/tutorial/essential/exceptions/… 了解更多信息。
      猜你喜欢
      • 2021-07-28
      • 1970-01-01
      • 1970-01-01
      • 2015-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多