【问题标题】:Finding two free tcp ports找到两个空闲的 tcp 端口
【发布时间】:2011-03-17 00:01:55
【问题描述】:

我知道下面的代码可以(可能不是很有效)在 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 方法的调用)。

这是正确的吗?

【问题讨论】:

  • 如果有相关问题,您应该引用它们并链接到它们。
  • 由于 SO_WAIT 而没有重新分配它,这是一种旨在避免仍在传输中的数据包会被另一个进程接收的机制。默认情况下,关闭一个 TCP 端口,在接下来的 2 分钟内不会重新分配它以允许这些滞留数据包刷新。
  • 在我看来,这种行为可能很常见,但只是依赖于实现,不是吗? tcpipguide.com/free/…technet.microsoft.com/en-us/library/cc759700(v=ws.10).aspx
  • 我不知道这是否是一个标准,但绝对是一个很好的安全/隐私措施。

标签: java sockets tcp


【解决方案1】:

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

【讨论】:

  • 应该注意的是,即使这个解决方案(和 Noel M 的)也不是 100% 万无一失的,存在潜在的竞争条件。在这个方法调用之后,调用者最终会尝试使用那些可用的端口。但也有可能同时其他进程打开了它。
【解决方案2】:

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

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

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

【讨论】:

  • 我想你的意思是socket1.getLocalPort()socket2.getLocalPort()
【解决方案3】:

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 的连续调用不会重用该端口,从而保证两个不同的端口。

【讨论】:

  • 但是findFreePort打开socket并立即关闭它,所以理论上又是可用的。
  • 在代码中,端口被分配,但是“close()”方法取消分配这个端口。然后,它可以被重用(例如,由另一个 ServerSocket)。所以,我认为对该方法的另一个调用可能会给出相同的端口号。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

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

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

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

    【讨论】:

    • findFreePort() 在哪里;方法。 @克里斯
    • 就在那里,PortFinder 类的第一个成员。也许我把它放在字段声明之前的不寻常顺序弄糊涂了。
    猜你喜欢
    • 2016-04-10
    • 2013-05-17
    • 1970-01-01
    • 2018-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    相关资源
    最近更新 更多