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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/434718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:33:29  来源:igfitidea点击:

Sockets: Discover port availability using Java

javasocketsport

提问by user54075

How do I programmatically determine the availability of a port in a given machine using Java?

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

i.e given a port number, determine whether it is already being used or not?.

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

回答by Spencer Ruport

If you're not too concerned with performance, you could always try listening on a port using the ServerSocketclass. If it throws an exception odds are it's being used.

如果您不太关心性能,您可以随时尝试使用ServerSocket类侦听端口。如果它抛出异常,很可能它正在被使用。

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

EDIT:If all you're trying to do is select a free port then new ServerSocket(0)will find one for you.

编辑:如果您要做的只是选择一个免费端口,那么new ServerSocket(0)将为您找到一个。

回答by David Santamaria

This is the implementationcoming from the Apache camelproject:

这是实现从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;
}

They are checking the DatagramSocket as well to check if the port is avaliable in UDP and TCP.

他们也在检查 DatagramSocket 以检查端口是否在 UDP 和 TCP 中可用。

Hope this helps.

希望这可以帮助。

回答by Ivan

In my case it helped to try and connect to the port - if service is already present, it would respond.

在我的情况下,它有助于尝试连接到端口 - 如果服务已经存在,它会响应。

    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);              
    }

回答by TwentyMiles

It appears that as of Java 7, David Santamaria's answerdoesn't work reliably any more. It looks like you can still reliably use a Socket to test the connection, however.

从 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);
            }
        }
    }
}

回答by eivindw

For Java 7 you can use try-with-resource for more compact code:

对于 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;
    }
}

回答by Shmil The Cat

The try/catch socket based solutions , might not yield accurate results (the socket address is "localhost" and in some cases the port could be "occupied" not by the loopback interface and at least on Windows I've seen this test fails i.e. the prot falsely declared as available).

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

There is a cool library named SIGAR, the following code can hook you up :

有一个很酷的库叫做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;

回答by mayu jadhv

I have Tried something Like this and it worked really fine with me

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

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

                 }

回答by kmchmk

In my case I had to use DatagramSocket class.

就我而言,我不得不使用 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;
    }
}

Don't forget to import first

不要忘记先导入

import java.net.DatagramSocket;
import java.net.BindException;
import java.net.SocketException;

回答by JMax

The following solution is inspired by the SocketUtilsimplementation of Spring-core (Apache license).

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

Compared to other solutions using Socket(...)it is pretty fast (testing 1000 TCP ports in less than a second):

与使用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;
    }
}       

回答by Luke Hutchison

A cleanup of the answer pointed out by David Santamaria:

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;
    }
}

This is still subject to a race condition pointed out by user207421 in the comments to David Santamaria's answer (something could grab the port after this method closes the ServerSocketand DatagramSocketand returns).

这仍然是受user207421在评论大卫·圣玛丽亚的回答中指出的竞争条件(东西可以抓住港口此方法关闭后ServerSocketDatagramSocket返回)。