134

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

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

4

10 回答 10

94

这是来自 Apache camel项目的实现:

/**
 * 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 中可用。

希望这可以帮助。

于 2009-01-12T14:31:54.040 回答
41

对于 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;
    }
}
于 2013-03-11T13:50:15.440 回答
38

如果您不太关心性能,您可以随时尝试使用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)会为您找到一个。

于 2009-01-12T07:47:54.633 回答
38

从 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);
            }
        }
    }
}
于 2012-12-11T18:21:42.160 回答
11

以下解决方案的灵感来自 Spring-core(Apache 许可)的SocketUtils实现。

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

当然,它只能检测在所有接口上打开端口或在 localhost 上显式运行的服务。

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;
    }
}       
于 2018-02-16T13:56:59.727 回答
3

基于 try/catch 套接字的解决方案可能不会产生准确的结果(套接字地址是“localhost”,并且在某些情况下,端口可能不会被环回接口“占用”,至少在 Windows 上我已经看到此测试失败,即prot 被错误地声明为可用)。

有一个很酷的库,名为SIGAR,下面的代码可以帮你搞定:

Sigar sigar = new Sigar();
int flags = NetFlags.CONN_TCP | NetFlags.CONN_SERVER | NetFlags.CONN_CLIENT;             NetConnection[] netConnectionList = sigar.getNetConnectionList(flags);
for (NetConnection netConnection : netConnectionList) {
   if ( netConnection.getLocalPort() == port )
        return false;
}
return true;
于 2013-03-12T18:34:57.313 回答
3

David Santamaria 指出的答案的清理:

/**
 * Check to see if a port is available.
 *
 * @param port
 *            the port to check for availability.
 */
public static boolean isPortAvailable(int port) {
    try (var ss = new ServerSocket(port); var ds = new DatagramSocket(port)) {
        return true;
    } catch (IOException e) {
        return false;
    }
}

这仍然取决于 user207421 在对 David Santamaria 的回答的评论中指出的竞争条件(在此方法关闭ServerSocketandDatagramSocket并返回后,某些东西可能会抢占端口)。

于 2019-03-08T05:43:51.513 回答
1

就我而言,它有助于尝试连接到端口 - 如果服务已经存在,它会响应。

    try {
        log.debug("{}: Checking if port open by trying to connect as a client", portNumber);
        Socket sock = new Socket("localhost", portNumber);          
        sock.close();
        log.debug("{}: Someone responding on port - seems not open", portNumber);
        return false;
    } catch (Exception e) {         
        if (e.getMessage().contains("refused")) {
            return true;
    }
        log.error("Troubles checking if port is open", e);
        throw new RuntimeException(e);              
    }
于 2012-05-31T05:52:34.567 回答
0

就我而言,我必须使用 DatagramSocket 类。

boolean isPortOccupied(int port) {
    DatagramSocket sock = null;
    try {
        sock = new DatagramSocket(port);
        sock.close();
        return false;
    } catch (BindException ignored) {
        return true;
    } catch (SocketException ex) {
        System.out.println(ex);
        return true;
    }
}

不要忘记先导入

import java.net.DatagramSocket;
import java.net.BindException;
import java.net.SocketException;
于 2017-11-06T13:46:37.097 回答
-2

我已经尝试过这样的事情,它对我来说真的很好

            Socket Skt;
            String host = "localhost";
            int i = 8983; // port no.

                 try {
                    System.out.println("Looking for "+ i);
                    Skt = new Socket(host, i);
                    System.out.println("There is a Server on port "
                    + i + " of " + host);
                 }
                 catch (UnknownHostException e) {
                    System.out.println("Exception occured"+ e);

                 }
                 catch (IOException e) {
                     System.out.println("port is not used");

                 }
于 2015-10-28T06:56:11.990 回答