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

标签 java udp nio

我正在实现一个发现流程:

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

第一次通话成功。但其他调用会出现绑定(bind)错误。地址已被使用:绑定(bind)

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

netstat -a -b -sp udp | netstat -a -b -sp udp | grep 55224

UDP 0.0.0.0:55224 :

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

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

我运行了 2 个测试,一个使用 NIO channel ,另一个不使用(来自在网上找到的测试)。我用 NIO 版本重现了我的错误,但如果我不使用 NIO,它就会工作。

任何人都可以告诉我如何让它与 NIO 一起工作。目标平台是 Android,我不想总是监听广播,而只是重复一段时间。

测试套接字

    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):地址已在使用中:无法绑定(bind)

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

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

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

结束...


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

使用 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 被注释,则测试有效..


channel 结果

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

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

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


感谢您的帮助

最佳答案

I did get some errors but the socket get closed properly... which is oki for my needs

不,如果您遇到错误,则说明您的 channel 未正确关闭。

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

关于java - DatagramChannel.close() 在 Windows 上保持端口打开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12977164/

相关文章:

Java Mysql 连接检查测试

java - 如何转换代码以使用CompletableFuture?

java - 无法通过 putExtra 将 HashMap 发送到新 Activity

java - 正则表达式提取范围内的数字

Java UDP服务器-客户端通信-发送分片(分片发送失败)

java - DatagramSocket能否接收多播数据包

linux - 通过sysctl进行性能调优,设置net.core.rmem_default (r/w)/net.ipv4.tcp_mem/net.ipv4.udp_mem有什么区别

java - 为什么 Cassandra 客户端在生产中没有 epoll 会失败?

Java NIO无法从JRT镜像中读取文件

java - 更改文件长度时,是否需要重新映射所有关联的 MappedByteBuffer?