找到两个免费的TCP端口

时间:2010-07-16 14:22:45

标签: java sockets tcp

据我所知,以下代码可以(可能不是非常有效)在Java中找到一个免费的TCP端口:

  public static int findFreePort() {
    int port;
    try {
      ServerSocket socket= new ServerSocket(0);
      port = socket.getLocalPort();
      socket.close(); 
    } catch (Exception e) { port = -1; }
    return port;    
  } 

(SO中有一些相关问题 - for example)。

我不明白为什么(或者是否)对这种方法的两次成功调用保证返回两个不同的端口。例如,假设here(搜索对findFreePort方法的调用)。

这是对的吗?

5 个答案:

答案 0 :(得分:5)

在Javadoc规范中,我没有看到任何一行说两个成功的呼叫保证返回两个不同的端口......

由于ServerSocket已关闭,第二次调用可能会提供相同的端口。从统计上来说,这是不可能的,但我认为并非不可能。

如果打开两个ServerSocket,获取端口,然后关闭两个ServerSocket,则需要获得两个不同的端口(因为第一个在创建第二个ServerSocket时不是免费的)。

获取n个不同空闲端口的示例方法:

public int[] getFreePorts(int portNumber) throws IOException {
    int[] result = new int[portNumber];
    List<ServerSocket> servers = new ArrayList<ServerSocket>(portNumber);
    ServerSocket tempServer = null;

    for (int i=0; i<portNumber; i++) {
        try {
            tempServer = new ServerSocket(0);
            servers.add(tempServer);
            result[i] = tempServer.getLocalPort();
        } finally {
            for (ServerSocket server : servers) {
                try {
                    server.close();
                } catch (IOException e) {
                    // Continue closing servers.
                }
            }
        }
    }
    return result;
}

答案 1 :(得分:2)

获得两个不同端口号的一种方法:

  ServerSocket socket1 = new ServerSocket(0);
  port1 = socket1.getLocalPort();
  ServerSocket socket2 = new ServerSocket(0);
  port2 = socket2.getLocalPort();

  socket1.close();
  socket2.close(); 

答案 2 :(得分:0)

ServerSocket的源代码在这里:http://kickjava.com/src/java/net/ServerSocket.java.htm

我不太确定它是如何确定端口是否空闲,但是:

@param port the port number, or <code>0</code> to use any
free port.

因此,一旦分配了第一个端口,甚至是您的应用程序,它就不再是免费的。因此,对ServerSocket的连续调用将不会重用该端口,从而保证两个不同的端口。

答案 3 :(得分:0)

它与操作系统一样高效。但是,之后立即关闭ServerSocket是没有意义的,因为该端口不再保留,可以分配给其他东西。本练习的唯一目的是创建一个ServerSocket,所以只需创建它。

答案 4 :(得分:0)

这是我用来查找多个空闲端口的类。它提供了在一些复杂逻辑流中分配各个端口的灵活性(即,当您需要的端口数量可能不是一个简单的数字但依赖于复杂的逻辑时)。它仍然保证您要求的所有端口都是免费且唯一的(只要您使用此类的相同实例来获取所有端口)。

所以使用这个类的方法是创建一个实例。执行您的代码以执行您希望为使用该实例分配端口的任何操作。然后,一旦绑定了所有端口,就可以处理此实例并在下次使用新实例。

public class PortFinder {

/**
 * If you only need the one port you can use this. No need to instantiate the class
 */
public static int findFreePort() throws IOException {
    ServerSocket socket = new ServerSocket(0);
    try {
        return socket.getLocalPort();
    } finally {
        try {
            socket.close();
        } catch (IOException e) {
        }
    }
}

private HashSet<Integer> used = new HashSet<Integer>();

/**
 * Finds a port that is currently free and is guaranteed to be different from any of the
 * port numbers previously returned by this PortFinder instance.
 */
public synchronized int findUniqueFreePort() throws IOException {
    int port;
    do {
        port = findFreePort();
    } while (used.contains(port));
    used.add(port);
    return port;
}

}