我想啓動一個監聽端口的服務器。我可以明確指定端口並且它可以工作。但我想自動找到一個端口。在這方面我有兩個問題。如何查找可用端口?
我應該在哪個範圍的端口號搜索? (我用端口12345,12346和12347,這很好)。
如何才能知道給定的端口是否未被其他軟件佔用?
我想啓動一個監聽端口的服務器。我可以明確指定端口並且它可以工作。但我想自動找到一個端口。在這方面我有兩個問題。如何查找可用端口?
我應該在哪個範圍的端口號搜索? (我用端口12345,12346和12347,這很好)。
如何才能知道給定的端口是否未被其他軟件佔用?
如果您不介意使用的端口,請將端口指定爲0到ServerSocket constructor,它將偵聽任何空閒端口。
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");
}
如果您的服務器啓動,那麼沒有使用該套接字。
編輯
喜歡的東西:
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));
}
不要知道是誰投票給你,但我投票支持你。你可以設置一個遞歸函數來嘗試設置ServerSocket,如果你得到一個IOException(或者其他情況),你可以再試一次,直到成功獲取一個端口。 – jonescb 2010-04-20 13:22:14
我認爲最好檢查一個端口是否可用,然後嘗試開始監聽這個端口。開始某件事情似乎並不高雅,然後發現存在一些問題,然後嘗試解決這些問題。 – Roman 2010-04-20 13:22:57
@羅曼好,是的,那樣會更好,除了事實上沒有一種方法可以知道端口是否可用。如果'新的ServerSocket(0)'不適合你的替代方案是這樣的。我認爲,使用我的建議最終有85%的可能性。 – OscarRyz 2010-04-20 16:27:46
據Wikipedia,你應該使用的端口49152
到65535
如果你並不需要一個 '衆所周知' 的端口。
AFAIK確定是否正在使用端口的唯一方法是嘗試打開端口。
+1。由於維基百科並不總是絕對真理/事實的來源,我認爲可能有用的是,該維基百科頁面的引用來自「互聯網號碼分配機構(IANA)的」[服務名稱和傳輸協議端口號註冊表(https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml)]「頁面,基於[RFC 6335 - 第6節](https:// tools.ietf.org/html/rfc6335#section-6)(即在這種情況下「固體」引用!:))。 – OzgurH 2017-08-24 09:30:09
如果您將0作爲端口號傳遞給ServerSocket的構造函數,它將爲您分配一個端口。
是的,我認爲這是最優雅的解決方案,但由於某些原因,它不適用於我的情況。但我仍然需要找出究竟是什麼錯誤。 – Roman 2010-04-20 13:25:09
@羅曼,發佈你的代碼,讓我們來找出 – OscarRyz 2010-04-20 13:29:41
@羅曼:爲什麼它不起作用?更新您的問題以包含此問題(或者人們會不斷提出建議),並解釋爲什麼此解決方案不適合您。 – FrustratedWithFormsDesigner 2010-04-20 13:30:44
見http://java.sun.com/j2se/1.4.2/docs/api/java/net/ServerSocket.html#ServerSocket%28int%29
創建服務器套接字綁定到指定的端口。 0的端口在任何空閒端口上創建一個套接字。
Eclipse SDK包含一個類SocketUtil,它可以做你想做的。你可以看看git source code。
看着Eclipse的代碼,他們做的事情與Graham Edgecombe的回答 – KevinL 2015-03-07 18:21:50
它可能沒有多大幫助,但在我的(Ubuntu)機器上,我有一個文件/ etc/services,其中至少有一些應用程序使用/保留的端口被給出。這些是這些應用程序的標準端口。
不保證這些應用程序正在運行,只是這些應用程序使用的默認端口(所以如果可能,您不應該使用它們)。
定義的端口略多於500個,大約一半的UDP和一半的TCP。
這些文件是使用IANA提供的信息製作的,請參閱IANA Assigned port numbers。
一樣,有一個類似的(更完整的IIRC)列表,它是nmap的一部分。 +1 – rmeador 2010-04-20 14:05:38
這對我的作品在Java 6
ServerSocket serverSocket = new ServerSocket(0);
System.out.println("listening on port " + serverSocket.getLocalPort());
如果你想使用ServerSocket
創建自己的服務器,你可以有它選擇一個空閒端口爲您提供:
ServerSocket serverSocket = new ServerSocket(0);
int port = serverSocket.getLocalPort();
其他服務器實現通常有類似的支持。 碼頭例如挑選一個空閒的端口,除非你明確地設置:
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
// don't call: connector.setPort(port);
server.addConnector(connector);
server.start();
int port = connector.getLocalPort();
如果你使用Spring,你可以嘗試http://docs.spring.io/spring/docs/4.0.5.RELEASE/javadoc-api/org/springframework/util/SocketUtils.html#findAvailableTcpPort--
這應該是答案。爲我工作 – ferronrsmith 2014-07-24 22:39:09
從Java 1.7開始,你可以使用try-與資源這樣的:
private Integer findRandomOpenPortOnAllLocalInterfaces() throws IOException {
try (
ServerSocket socket = new ServerSocket(0);
) {
return socket.getLocalPort();
}
}
如果您需要查找特定接口上的開放端口,請查閱ServerSocket替代構造函數的文檔。
警告:使用此方法返回的端口號的任何代碼是受競爭情況 - 不同的進程/線程可能結合到同一個端口後我們關閉ServerSocket實例。
如果您未設置「SO_REUSEADDR」,則這可能不起作用。還有一個競爭條件,但很難解決這個問題。 – 2015-06-29 04:40:21
如果您隨後嘗試使用相同的端口號打開*另一個*'ServerSocket',則可能無法正常工作,因爲它可能在此期間被佔用。爲什麼你不會返回實際的'ServerSocket'而不是關閉它仍然是一個謎。 – EJP 2017-03-22 09:46:18
我最近剛剛發佈了一個小圖書館,只是考慮到了這一點。 Maven的依賴是:
<dependency>
<groupId>me.alexpanov</groupId>
<artifactId>free-port-finder</artifactId>
<version>1.0</version>
</dependency>
一旦安裝,免費的端口號可以通過獲得:
int port = FreePortFinder.findFreeLocalPort();
如果您在範圍需要使用:
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;
}
}
想知道如何檢查一個端口,然後解除綁定。謝謝SergeyB! – 2016-04-05 06:24:56
如果[from,to]範圍內的每個端口都處於使用狀態,則此代碼將無限循環(或至少直到其中一個端口變爲空閒狀態)。如果您執行順序掃描而不是隨機選擇範圍內的端口,則可以避免出現這種可能性(只是在未找到空閒端口的情況下到達範圍末尾時發出異常)。如果您確實需要隨機選擇端口,那麼您需要一組記錄迄今嘗試過的端口,然後在該組的大小等於 - from時引發錯誤。 – 2016-12-15 05:33:19
使用新的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 – vorburger 2012-08-22 22:09:59
@vorburger,做它以這種方式很容易出現競賽狀況。更好地立即監聽服務器套接字,而不是打開它來查找空閒端口,再次關閉它,然後在空閒端口上再次打開一個端口(此時有一小部分機會現在正在監聽端口。) – 2012-09-04 12:49:50
同意了,但它取決於確切的用例:在我的情況下,我需要找到一個自由端口號將它交給一些API(比如嵌入式Jetty啓動器,用於測試) - 相應的API需要一個套接字號 - 不是已經打開的服務器套接字。這取決於。 – vorburger 2012-09-14 11:44:55