利用可能なポートを見つける方法は?


194

ポートをリッスンするサーバーを起動したいのですが。私は明示的にポートを指定することができ、それは動作します。しかし、私は自動的にポートを見つけたいと思っています。この点で2つの質問があります。

  1. どのポート番号の範囲で検索する必要がありますか?(ポート12345、12346、12347を使用しましたが、問題ありませんでした)。

  2. 特定のポートが別のソフトウェアによって占有されていないかどうかを確認するにはどうすればよいですか?

回答:


277

使用するポートが問題ない場合は、ServerSocketコンストラクターに0のポートを指定すると、空いているポートで待機します。

ServerSocket s = new ServerSocket(0);
System.out.println("listening on port: " + s.getLocalPort());

特定のポートのセットを使用したい場合、最も簡単な方法は、1つが機能するまでそれらを反復処理することです。このようなもの:

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

2
新しいServerSocket(0)を使用するときは、それを閉じるように注意する必要があります。javasourcecode.org/html/open-source/eclipse/eclipse-3.5.2/org/…に基づいており、私のgist.github.com/3429822でわずかに変更
vorburger

9
@vorburger、その方法でそれを行うと、競合状態になりがちです。空きポートを見つけるために開いてもう一度閉じ、次に空きポートでもう一度開くよりも、サーバーソケットをすぐにリッスンするだけの方がいいです(その時までに、他の何かがそのポートでリッスンしている可能性はわずかです)ポート。)
Graham Edgecombe 2012

7
同意しましたが、それは正確な使用例に依存します:私の場合、それをいくつかのAPIに渡すために空きポート番号を見つける必要がありました(たとえば、テスト用の組み込みJettyスターター)-それぞれのAPIはソケット番号を要求しています-まだではありません開かれたサーバーソケット。したがって、状況によって異なります。
vorburger 2012

4
@vorburger Reasonable APIは、待機する有効なポート番号としてゼロを受け入れ、待機している実際のポートを通知します。Hovewerには、妥当なAPIは多くありません。多くのプログラムは、0ポートが渡されるssh -D 127.0.0.0:0 ...かどうかを具体的にテストし、それを拒否します(?いいえ!)。これは本当にイライラします。それらを使用できるようにするには、かなりの数のライブラリ/プログラムにパッチを適用する必要がありました。
Joker_vD 2014年

2
@vorburger ポートを使用するときはポートを閉じるように注意する必要があります。new ServerSocket(0)この点で違いはありません。これに関する最初のリンクには何もありません。2番目のリンクは単に練習不足を示しています。いったん作成しServerSocketたら、それを使用する必要があります。閉じるのではなく、同じポート番号を再利用してください。これらはすべて時間の無駄であり、タイミングウィンドウの問題に対して脆弱です。
ローン侯爵

57

ServerSocketのコンストラクターにポート番号として0を渡すと、ポートが割り当てられます。


はい、これは最もエレガントなソリューションだと思いますが、いくつかの理由により、私の場合は機能しません。しかし、私はまだ何が間違っているのかを見つける必要があります。
ローマ

1
@ローマン:なぜ動かないの?これを含めるように質問を更新し(または他の人が提案し続けるでしょう)、このソリューションが失敗する理由を説明します。
FrustratedWithFormsDesigner

2
クライアントからこのポートを見つけるにはどうすればよいですか?;)
ed22

34

Java 1.7以降では、try-with-resourcesを次のように使用できます。

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

    }
  }

特定のインターフェースで開いているポートを見つける必要がある場合は、ServerSocketのドキュメントで代替コンストラクタを確認してください。

警告:このメソッドによって返されるポート番号を使用するコードはすべて競合状態の影響を受けます。ServerSocketインスタンスを閉じた直後に、別のプロセス/スレッドが同じポートにバインドする場合があります。


1
設定しない場合、これは機能しない可能性がありますSO_REUSEADDR。そして、競合状態がありますが、それを修正するのは困難です。
David Ehrmann、2015年

その間に別の ServerSocketポート番号が使用されている可能性があるため、後で同じポート番号で別のポート番号を開こうとすると、これが機能しない可能性があります。なぜあなたはServerSocketそれを閉じるのではなく単に実際のものを返さないのかは謎のままです。
ローンの侯爵

5
@EJPサードパーティのコードがポートを受け入れるが、ソケット自体を受け入れない場合があります。
キャプテンマン

@CaptainManもちろんですが、そのような場合、ポートは事前に割り当てられていると想定されます。動的に割り当てられたポートは、ネーミングサービス、ブロードキャスト、マルチキャストなど、他のメカニズムによってクライアントに提供する必要があります。ここでの質問全体は奇妙です。
ローン侯爵

@ user207421 ただし、ポートのServerSocket代わりにを受け入れるようにサードパーティのコードを変更することはできませんint
キャプテンマン

30

Wikipediaによると、「よく知られた」ポートが必要ない場合は、ポート49152を使用する65535必要があります。

私の知る限り、ポートが使用されているかどうかを判断する唯一の方法は、ポートを開こうとすることです。


6
+1。Wikipediaは必ずしも絶対的な真実/事実の源であるとは限らないので、そのWikipediaページの参照は「Internet Assigned Numbers Authority(IANA)」の「[Service Name and Transport Protocol Port Numberレジストリ(iana.org/assignments/service-names-port-numbers/… "ページ、RFC 6335-セクション6に基づく(つまり、この場合は「固体」参照!)
OzgurH 2017

25

範囲内で使用する必要がある場合:

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、ありがとう!
Vlad Ilie 2016

5
[from、to)の範囲のすべてのポートが使用中の場合、このコードは無限に(または少なくともこれらのポートの1つが解放されるまで)ループします。範囲内のポートをランダムに選択するのではなく、順次スキャンを実行すると、この可能性を回避できます(空きポートが見つからずに範囲の最後に到達したときに例外をスローするだけです)。本当にランダムにポートを選択する必要がある場合は、これまでに試したポートを追跡するためのセットが必要であり、そのセットのサイズが-fromに等しいときにエラーを発生させます。
Simon Kissane、2016

ポート0はかなり単純ServerSocketsで、成功した場合に2つを作成する必要がなく、このコードのタイミングウィンドウの問題の影響を受けません。
ローン侯爵

21

好奇心が強い人のために、内部でSpringUtils.findAvailableTcpPort()は他の回答で推奨されているのとまったく同じことをしています:ポートを選択してからを試してくださいnew ServerSocket(port)
Alexey Berezkin

11

Eclipse SDKには、必要な処理を実行するSocketUtilクラスが含まれています。gitのソースコードを調べてみてください。


2
Eclipseのコードを見ると、彼らはGraham Edgecombeの回答と同じことをしています
KevinL


6

これは私にとってJava 6で機能します

    ServerSocket serverSocket = new ServerSocket(0);
    System.out.println("listening on port " + serverSocket.getLocalPort());

6

私は最近、テストを念頭に置いてそれを行うための小さなライブラリをリリースしました。Mavenの依存関係は次のとおりです。

<dependency>
    <groupId>me.alexpanov</groupId>
    <artifactId>free-port-finder</artifactId>
    <version>1.0</version>
</dependency>

インストールすると、次の方法で空きポート番号を取得できます。

int port = FreePortFinder.findFreeLocalPort();

4

サーバーが起動した場合、そのソケットは使用されていません。

編集

何かのようなもの:

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

ポートが利用可能かどうかを確認してから、このポートのリスニングを開始することをお勧めします。何かを始めて、いくつかの問題があることを見つけて、これらの問題を解決しようとするのはエレガントではないようです。
ローマ

2
@Romanまあ、そうです、ポートが利用可能かどうかを知る方法がないという事実を除いて、それはより良いでしょう。new ServerSocket(0)あなたの代わりにうまくいかない場合はこれがこれです。私の提案を使用してしまう可能性は85%あると思います。
OscarRyz 2010

このコードは、オープンとリークをServerSockets永久に続け、成功した最後のコードのみを保持します。breakステートメントが必要です。
ローン侯爵

4

を使用して独自のサーバーを作成する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();

3

それはあまり役に立たないかもしれませんが、私の(Ubuntu)マシンには、少なくとも一部のアプリが使用/予約するポートが指定された/ etc / servicesファイルがあります。これらはこれらのアプリの標準ポートです。

これらが動作している保証はなく、これらのアプリが使用するデフォルトのポートのみです(したがって、可能であれば使用しないでください)。

500をわずかに超える数のポートが定義されており、半分はUDP、半分はTCPです。

ファイルはIANAの情報を使用して作成されます。IANA割り当てポート番号を参照してください。


nmapの一部として提供される同様の(より完全なIIRC)リストがあります。+1
rmeador 2010

3

Springを使用している場合、Michail Nikolaevによって提供された答えが最も単純で最もきれいなものであり、IMOを支持する必要があります。便宜上、Springframwework SocketUtils .findAvailableTcpPort()メソッドを使用してインラインの例を追加します。

int randomAvailablePort = SocketUtils.findAvailableTcpPort();

それはそれと同じくらい簡単で、1行だけです:)。もちろん、Utilsクラスは他の多くの興味深いメソッドを提供します。ドキュメントを参照することをお勧めします。


1

'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) {

         }
}

参照リンク


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.