Answers:
如果您不介意使用的端口,请为ServerSocket构造函数指定端口0,它将侦听任何可用端口。
ServerSocket s = new ServerSocket(0);
System.out.println("listening on port: " + s.getLocalPort());
如果要使用一组特定的端口,那么最简单的方法可能是遍历它们直到一个端口起作用为止。像这样:
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");
}
可以这样使用:
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");
}
ssh -D 127.0.0.0:0 ...
?否!),这确实令人沮丧。我们必须修补许多库/程序,以使它们对我们有用。
new ServerSocket(0)
在这方面没有什么不同。您的第一个链接中没有关于此的任何内容。您的第二个链接仅表现为不良实践。构建完之后ServerSocket
,就应该使用它,而不要关闭它它并尝试重用相同的端口号。所有这些都完全浪费时间,并且容易受到时序窗口问题的影响。
如果将0作为端口号传递给ServerSocket的构造函数,它将为您分配一个端口。
从Java 1.7开始,您可以使用如下try-with-resources:
private Integer findRandomOpenPortOnAllLocalInterfaces() throws IOException {
try (
ServerSocket socket = new ServerSocket(0);
) {
return socket.getLocalPort();
}
}
如果需要在特定接口上找到开放端口,请检查 ServerSocket文档以获取替代构造函数。
警告:使用此方法返回的端口号的任何代码都必须遵守竞争条件-关闭ServerSocket实例后,不同的进程/线程可能会立即绑定到同一端口。
SO_REUSEADDR
。虽然存在比赛条件,但很难解决。
ServerSocket
端口,则此方法可能不起作用,因为这可能是在此同时进行的。为什么您不只是返回实际值ServerSocket
而不是关闭它仍然是一个谜。
ServerSocket
代替int
。
根据Wikipedia所述,您应该使用端口49152
来65535
,如果你并不需要一个“众所周知”的端口。
AFAIK确定端口正在使用的唯一方法是尝试打开它。
如果您需要在范围内使用:
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;
}
}
ServerSockets
在成功的情况下不需要创建两个端口,并且不会遭受此代码的计时窗口问题。
如果您使用Spring,则可以尝试http://docs.spring.io/spring/docs/4.0.5.RELEASE/javadoc-api/org/springframework/util/SocketUtils.html#findAvailableTcpPort--
SpringUtils.findAvailableTcpPort()
下做的与其他答案中建议的完全相同:选择一个端口,然后尝试new ServerSocket(port)
。
Eclipse SDK包含一个SocketUtil类,它可以满足您的需求。您可以查看git 源代码。
参见http://java.sun.com/j2se/1.4.2/docs/api/java/net/ServerSocket.html#ServerSocket%28int%29
创建绑定到指定端口的服务器套接字。端口0会在任何空闲端口上创建一个套接字。
我最近发布了一个小型库,它考虑了测试的目的。Maven依赖项是:
<dependency>
<groupId>me.alexpanov</groupId>
<artifactId>free-port-finder</artifactId>
<version>1.0</version>
</dependency>
安装后,可以通过以下方式获取免费端口号:
int port = FreePortFinder.findFreeLocalPort();
如果服务器启动,则不使用该套接字。
编辑
就像是:
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));
}
new ServerSocket(0)
对您不起作用,替代方法是这样。我认为您最终有85%的可能性会使用我的建议。
ServerSockets
永远保持打开和泄漏的状态,只保留最后一个成功的代码。它需要一个break
声明。
如果您想使用来创建自己的服务器ServerSocket
,则可以让它为您选择一个空闲端口:
ServerSocket serverSocket = new ServerSocket(0);
int port = serverSocket.getLocalPort();
其他服务器实现通常具有类似的支持。例如,Jetty选择一个空闲端口,除非您明确设置它:
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
// don't call: connector.setPort(port);
server.addConnector(connector);
server.start();
int port = connector.getLocalPort();
它可能对您没有太大帮助,但是在我的(Ubuntu)机器上,我有一个/ etc / services文件,其中至少给出了某些应用程序使用/保留的端口。这些是这些应用程序的标准端口。
无法保证它们正在运行,只能保证这些应用程序使用的默认端口(因此,如果可能的话,请勿使用它们)。
定义了略多于500个的端口,大约一半是UDP,一半是TCP。
这些文件是使用IANA的信息制作的,请参阅IANA分配的端口号。
如果您使用的是Spring,则Michail Nikolaev提供的答案是最简单,最简洁的答案,应该赞成IMO。为了方便起见,我将使用Springframwework SocketUtils .findAvailableTcpPort()方法添加一个内联示例:
int randomAvailablePort = SocketUtils.findAvailableTcpPort();
就这么简单,只需一行:)。当然,Utils类提供了许多其他有趣的方法,我建议您看一下文档。
使用“ ServerSocket”类,我们可以确定给定端口是正在使用还是空闲。ServerSocket提供了一个构造函数,该构造函数使用整数(即端口号)作为参数并初始化端口上的服务器套接字。如果ServerSocket引发任何IO异常,则可以假定此端口已在使用中。
以下代码段用于获取所有可用端口。
for (int port = 1; port < 65535; port++) {
try {
ServerSocket socket = new ServerSocket(port);
socket.close();
availablePorts.add(port);
} catch (IOException e) {
}
}
参考链接。
如果端口被其他软件占用,则代码将抛出IOException