如何找到可用的端口?

Rom*_*man 188 java sockets port networking

我想启动一个监听端口的服务器.我可以明确指定端口,它可以工作.但我想以自动方式找到一个端口.在这方面,我有两个问题.

  1. 我应该在哪个端口号范围内搜索?(我使用了端口12345,12346和12347,它很好).

  2. 如何确定某个端口是否未被其他软件占用?

Gra*_*mbe 264

如果您不介意使用的端口,请为ServerSocket构造函数指定一个0的端口,它将侦听任何空闲端口.

ServerSocket s = new ServerSocket(0);
System.out.println("listening on port: " + s.getLocalPort());
Run Code Online (Sandbox Code Playgroud)

如果你想使用一组特定的端口,那么最简单的方法就是迭代它们直到一个工作.像这样的东西:

public ServerSocket create(int[] ports) throws IOException {
    for (int port : ports) {
        try {
            return new ServerSocket(port);
        } catch (IOException ex) {
            continue; // try next port
        }
    }

    // if the program gets here, no port in the range was found
    throw new IOException("no free port found");
}
Run Code Online (Sandbox Code Playgroud)

可以像这样使用:

try {
    ServerSocket s = create(new int[] { 3843, 4584, 4843 });
    System.out.println("listening on port: " + s.getLocalPort());
} catch (IOException ex) {
    System.err.println("no available ports");
}
Run Code Online (Sandbox Code Playgroud)

  • @vorburger,以这种方式做这件事很容易出现竞争条件.只是立即监听服务器套接字,而不是打开它以找到一个空闲端口,然后再次关闭它,然后再在空闲端口上打开一个(此时有一点其他东西现在正在监听港口.) (9认同)
  • 同意,但这取决于确切的用例:在我的情况下,我需要找到一个自由端口号将其交给某些API(比如一个嵌入式Jetty启动器,用于测试) - 相应的API需要一个套接字号 - 而不是已经打开服务器套接字 所以这取决于. (5认同)
  • @vorburger合理的API将接受零作为要侦听的有效端口号,然后将告诉您正在侦听的实际端口.Hovewer,没有太多合理的API:许多程序专门测试0端口被传递并拒绝它(`ssh -D 127.0.0.0:0 ......`?Nope!),这真的令人沮丧.我们必须修补相当多的库/程序,以便它们对我们有用. (4认同)
  • 使用 new ServerSocket(0) 时,要注意关闭它!基于 http://javasourcecode.org/html/open-source/eclipse/eclipse-3.5.2/org/eclipse/jdt/launching/SocketUtil.java.html,在我的 https://gist.github 中稍作修改。 com/3429822 (2认同)
  • @vorburger使用* any *端口时,应小心关闭它。在这方面`new ServerSocket(0)'没什么不同。您的第一个链接中没有关于此的任何内容。您的第二个链接仅表现为不良实践。一旦构建了ServerSocket,就应该*使用*,而不是* close *,并尝试重用相同的端口号。所有这些都是“完全浪费时间”,并且容易受到时序窗口问题的影响。 (2认同)

Mau*_*rry 54

如果将0作为端口号传递给ServerSocket的构造函数,它将为您分配一个端口.

  • 我如何从客户端找到这个端口?;) (6认同)

And*_*avu 31

从Java 1.7开始,您可以使用try-with-resources,如下所示:

  private Integer findRandomOpenPortOnAllLocalInterfaces() throws IOException {
    try (
        ServerSocket socket = new ServerSocket(0);
    ) {
      return socket.getLocalPort();

    }
  }
Run Code Online (Sandbox Code Playgroud)

如果需要在特定接口上查找开放端口,请检查ServerSocket文档以获取替代构造函数.

警告:使用此方法返回的端口号的任何代码都会受到竞争条件的影响 - 在关闭ServerSocket实例后,不同的进程/线程可能会立即绑定到同一端口.

  • @EJP有时第三方代码接受端口但不接受套接字本身. (5认同)

And*_*son 26

根据维基百科,你应该使用的端口4915265535,如果你并不需要一个"众所周知"的端口.

AFAIK确定端口正在使用的唯一方法是尝试打开它.

  • +1。由于Wikipedia并不总是绝对的事实/事实的来源,因此我认为有必要指出,该Wikipedia页面的引用来自“ Internet分配号码授权机构(IANA)”的“ [服务名称和传输协议端口号基于[RFC 6335-第6节](https:// tools.ietf.org/html/rfc6335#section-6)(即本例中的“ Solid”参考!:))。 (4认同)

Ser*_*kyi 21

如果您需要使用范围:

public int nextFreePort(int from, int to) {
    int port = randPort(from, to);
    while (true) {
        if (isLocalPortFree(port)) {
            return port;
        } else {
            port = ThreadLocalRandom.current().nextInt(from, to);
        }
    }
}

private boolean isLocalPortFree(int port) {
    try {
        new ServerSocket(port).close();
        return true;
    } catch (IOException e) {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果[from,to]范围内的每个端口都在使用中,则此代码将无限循环(或至少直到其中一个端口变为空闲).如果您执行顺序扫描而不是随机选择范围内的端口,则可以避免这种可能性(只有在到达范围结束时抛出异常而不查找空闲端口).如果您确实需要随机选择端口,那么您需要一个集来跟踪您到目前为止尝试过的端口,然后在该集合的大小等于 - 来自时引发错误. (4认同)

Mic*_*aev 20

如果您使用Spring,可以尝试http://docs.spring.io/spring/docs/4.0.5.RELEASE/javadoc-api/org/springframework/util/SocketUtils.html#findAvailableTcpPort--

  • 对于那些好奇的人,在底层“SpringUtils.findAvailableTcpPort()”正在执行与其他答案中建议的完全相同的操作:选择一个端口,然后尝试“new ServerSocket(port)”。 (3认同)
  • 不幸的是 `SocketUtils` 类现在已被弃用,并将在 Spring 6.0 中删除。 (3认同)

小智 11

Eclipse SDK包含一个类SocketUtil,它可以满足您的需求.您可以查看git 源代码.

  • 看看Eclipse的代码,他们就像Graham Edgecombe的回答一样 (2认同)

f1s*_*1sh 6

请参阅http://java.sun.com/j2se/1.4.2/docs/api/java/net/ServerSocket.html#ServerSocket%28int%29

创建绑定到指定端口的服务器套接字.端口0在任何空闲端口上创建套接字.


Pet*_*rey 6

这适用于Java 6

    ServerSocket serverSocket = new ServerSocket(0);
    System.out.println("listening on port " + serverSocket.getLocalPort());
Run Code Online (Sandbox Code Playgroud)


Osc*_*Ryz 5

如果您的服务器启动,则表明该套接字未被使用。

编辑

就像是:

ServerSocket s = null ;

try { 
    s = new ServerSocket( 0 ); 
} catch( IOException ioe ){
   for( int i = START; i < END ; i++ ) try {
        s = new ServerSocket( i );
    } catch( IOException ioe ){}
}
// At this point if s is null we are helpless
if( s == null ) {
    throw new IOException(
       Strings.format("Unable to open server in port range(%d-%d)",START,END));
}
Run Code Online (Sandbox Code Playgroud)

  • @Roman,是的,那会更好,除了没有办法知道端口是否可用。如果“new ServerSocket(0)”不适合您,则替代方法是这样。我认为您最终采用我的建议的可能性有 85%。 (2认同)

Ale*_*nov 5

我最近发布了一个小型库,它考虑了测试的目的。Maven依赖项是:

<dependency>
    <groupId>me.alexpanov</groupId>
    <artifactId>free-port-finder</artifactId>
    <version>1.0</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

安装后,可以通过以下方式获取免费端口号:

int port = FreePortFinder.findFreeLocalPort();
Run Code Online (Sandbox Code Playgroud)