找到两个空闲的 tcp 端口

Posted

技术标签:

【中文标题】找到两个空闲的 tcp 端口【英文标题】:Finding two free tcp ports 【发布时间】: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 我不知道这是否是一个标准,但绝对是一个很好的安全/隐私措施。 【参考方案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 类的第一个成员。也许我把它放在字段声明之前的不寻常顺序弄糊涂了。

以上是关于找到两个空闲的 tcp 端口的主要内容,如果未能解决你的问题,请参考以下文章

使用 Twisted python 是不是有一种机制可以找到类似于 socket.open 的空闲端口?

使用Twisted python,有一种机制可以找到类似于socket.open的空闲端口。

如何为子进程选择一个空闲端口?

C#判断一个端口是不是被占用以及返回一个空闲端口

端口为零的绑定会将您绑定到空闲端口。这是便携的吗? [关闭]

强制路由器保持空闲 UDP 端口打开