当前位置:  开发笔记 > 编程语言 > 正文

套接字:使用Java发现端口可用性

如何解决《套接字:使用Java发现端口可用性》经验,为你挑选了5个好方法。

如何使用Java以编程方式确定给定计算机中端口的可用性?

即给定一个端口号,确定它是否已被使用?



1> David Santam..:

这是实现从Apache来骆驼项目:

/**
 * Checks to see if a specific port is available.
 *
 * @param port the port to check for availability
 */
public static boolean available(int port) {
    if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) {
        throw new IllegalArgumentException("Invalid start port: " + port);
    }

    ServerSocket ss = null;
    DatagramSocket ds = null;
    try {
        ss = new ServerSocket(port);
        ss.setReuseAddress(true);
        ds = new DatagramSocket(port);
        ds.setReuseAddress(true);
        return true;
    } catch (IOException e) {
    } finally {
        if (ds != null) {
            ds.close();
        }

        if (ss != null) {
            try {
                ss.close();
            } catch (IOException e) {
                /* should not be thrown */
            }
        }
    }

    return false;
}

他们还检查DatagramSocket以检查端口是否可用于UDP和TCP.

希望这可以帮助.


然而,这并不能解决所有问题.我被TCP 8000上运行的nginx所困扰,而上述例程报告8000可用.不知道为什么 - 我怀疑nginx做了一些偷偷摸摸的东西(这是在OS X上).我的解决方法是执行上述操作并打开一个新的Socket("localhost",port),如果我们没有得到异常,则返回false.思考?
如果你有MINA,这个很好的变种是AvailablePortFinder.getNextAvailable(1024),它可以获得下一个非特权端口.
有趣.在套接字已经绑定之后,对setReuseAddress()的调用完全没有意义,它也完全违背了代码的用途.
这些代码受到时间窗问题的影响.如果目标是创建一个监听某个端口的`ServerSocket`,它应该做什么,并返回`ServerSocket`.创建它然后关闭它并返回它无法保证可以使用该端口创建后续的"ServerSocket".同样适用于`DatagramSocket`.
Windows上尝试检测papercut SMTP服务器是否正在运行时的相同问题.打开与端口的连接而不是尝试绑定到端口的解决方案(如Partly Clodys评论和Ivan的回答所示)似乎更可靠.

2> eivindw..:

对于Java 7,您可以使用try-with-resource来获得更紧凑的代码:

private static boolean available(int port) {
    try (Socket ignored = new Socket("localhost", port)) {
        return false;
    } catch (IOException ignored) {
        return true;
    }
}


这不会测试端口是否可用.它测试它是否处于LISTEN状态,IP地址是否可达等.

3> TwentyMiles..:

从Java 7开始,David Santamaria的答案似乎不再可靠.但是,看起来您仍然可以可靠地使用Socket来测试连接.

private static boolean available(int port) {
    System.out.println("--------------Testing port " + port);
    Socket s = null;
    try {
        s = new Socket("localhost", port);

        // If the code makes it this far without an exception it means
        // something is using the port and has responded.
        System.out.println("--------------Port " + port + " is not available");
        return false;
    } catch (IOException e) {
        System.out.println("--------------Port " + port + " is available");
        return true;
    } finally {
        if( s != null){
            try {
                s.close();
            } catch (IOException e) {
                throw new RuntimeException("You should handle this error." , e);
            }
        }
    }
}



4> Spencer Rupo..:

如果您不太关心性能,可以尝试使用ServerSocket类在端口上进行侦听.如果它抛出一个异常,它就被使用了.

public static boolean isAvailable(int portNr) {
  boolean portFree;
  try (var ignored = new ServerSocket(portNr)) {
      portFree = true;
  } catch (IOException e) {
      portFree = false;
  }
  return portFree;
}

编辑:如果你要做的就是选择一个免费端口,那么new ServerSocket(0)你会找到一个.


新的SeverSocket(0)将自动选择一个空闲端口.

5> JMax..:

以下解决方案的灵感来自Spring核心的SocketUtils实现(Apache许可证).

与使用Socket(...)它的其他解决方案相比,它非常快(在不到一秒的时间内测试1000个TCP端口):

public static boolean isTcpPortAvailable(int port) {
    try (ServerSocket serverSocket = new ServerSocket()) {
        // setReuseAddress(false) is required only on OSX, 
        // otherwise the code will not work correctly on that platform          
        serverSocket.setReuseAddress(false);
        serverSocket.bind(new InetSocketAddress(InetAddress.getByName("localhost"), port), 1);
        return true;
    } catch (Exception ex) {
        return false;
    }
}       

推荐阅读
路人甲
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有