1. 概要

Javaアプリケーションでソケットサーバーを起動する場合、 java.net APIでは、リッスンする空きポート番号を指定する必要があります。 ポート番号は、TCP層が着信データの対象となるアプリケーションを識別できるようにするために必要です。

ポート番号を明示的に指定することは、アプリケーションがすでにポート番号を占有している可能性があるため、必ずしも適切なオプションではありません。これにより、Javaアプリケーションで入出力例外が発生します。

このクイックチュートリアルでは、特定のポートステータスを確認する方法と、自動的に割り当てられたポートステータスを使用する方法を確認します。プレーンJavaおよびSpringフレームワークでこれを行う方法を確認します。 また、組み込みTomcatやJettyなどの他のサーバー実装についても見ていきます。

2. ポートステータスの確認

java .net APIを使用して、特定のポートが空いているか占有されているかを確認する方法を見てみましょう。

2.1. S特定のポート

を利用します ServerSocket からのクラス java .net 指定されたポートにバインドされたサーバーソケットを作成するためのAPI。 そのコンストラクターで 、ServerSocketは明示的なポート番号を受け入れます。 このクラスはCloseableインターフェースも実装しているため、try-with-resourcesで使用して、ソケットを自動的に閉じ、ポートを解放できます。

try (ServerSocket serverSocket = new ServerSocket(FREE_PORT_NUMBER)) {
    assertThat(serverSocket).isNotNull();
    assertThat(serverSocket.getLocalPort()).isEqualTo(FREE_PORT_NUMBER);
} catch (IOException e) {
    fail("Port is not available");
}

特定のポートを2回使用する場合、またはすでに別のアプリケーションによって占有されている場合、ServerSocketコンストラクターはIOExceptionをスローします。

try (ServerSocket serverSocket = new ServerSocket(FREE_PORT_NUMBER)) {
    new ServerSocket(FREE_PORT_NUMBER);
    fail("Same port cannot be used twice");
} catch (IOException e) {
    assertThat(e).hasMessageContaining("Address already in use");
}

2.2. P ort範囲

ここで、スローされた IOException、を使用して、指定された範囲のポート番号から最初の空きポートを使用してサーバーソケットを作成する方法を確認しましょう。

for (int port : FREE_PORT_RANGE) {
    try (ServerSocket serverSocket = new ServerSocket(port)) {
        assertThat(serverSocket).isNotNull();
        assertThat(serverSocket.getLocalPort()).isEqualTo(port);
        return;
    } catch (IOException e) {
        assertThat(e).hasMessageContaining("Address already in use");
    }
}
fail("No free port in the range found");

3. 空きポートを見つける

明示的なポート番号を使用することは必ずしも良いオプションではないので、空きポートを自動的に割り当てる可能性を調べてみましょう。

3.1. プレーンJava

ServerSocketクラスコンストラクターで特別なポート番号ゼロを使用できます。 その結果、 java.netAPIは自動的に空きポートを割り当てます。

try (ServerSocket serverSocket = new ServerSocket(0)) {
    assertThat(serverSocket).isNotNull();
    assertThat(serverSocket.getLocalPort()).isGreaterThan(0);
} catch (IOException e) {
    fail("Port is not available");
}

3.2. Spring Framework

Springフレームワークには、使用可能な空きポートを見つけるために使用できるSocketUtilsクラスが含まれています。 前の例に示すように、その内部実装はServerSocketクラスを使用します。

int port = SocketUtils.findAvailableTcpPort();
try (ServerSocket serverSocket = new ServerSocket(port)) {
    assertThat(serverSocket).isNotNull();
    assertThat(serverSocket.getLocalPort()).isEqualTo(port);
} catch (IOException e) {
    fail("Port is not available");
}

4. その他のサーバーの実装

次に、他の一般的なサーバー実装をいくつか見てみましょう。

4.1. 桟橋

Jettyは、Javaアプリケーションで非常に人気のある組み込みサーバーです。 ServerConnectorクラスのsetPortメソッドで明示的に設定しない限り、空きポートが自動的に割り当てられます。

Server jettyServer = new Server();
ServerConnector serverConnector = new ServerConnector(jettyServer);
jettyServer.addConnector(serverConnector);
try {
    jettyServer.start();
    assertThat(serverConnector.getLocalPort()).isGreaterThan(0);
} catch (Exception e) {
    fail("Failed to start Jetty server");
} finally {
    jettyServer.stop();
    jettyServer.destroy();
}

4.2. Tomcat

もう1つの人気のあるJava組み込みサーバーであるTomcatは、動作が少し異なります。 TomcatクラスのsetPortメソッドを使用して、明示的なポート番号を指定できます。 ポート番号0を指定すると、Tomcatは自動的に空きポートを割り当てます。ただし、ポート番号を設定しない場合、Tomcatはデフォルトのポート8080を使用します。 デフォルトのTomcatポートが他のアプリケーションによって占有されている可能性があることに注意してください。

Tomcat tomcatServer = new Tomcat();
tomcatServer.setPort(0);
try {
    tomcatServer.start();
    assertThat(tomcatServer.getConnector().getLocalPort()).isGreaterThan(0);
} catch (LifecycleException e) {
    fail("Failed to start Tomcat server");
} finally {
    tomcatServer.stop();
    tomcatServer.destroy();
}

5. 結論

この記事では、特定のポートステータスを確認する方法について説明しました。 また、さまざまなポート番号から空きポートを見つける方法についても説明し、自動的に割り当てられた空きポートの使用方法について説明しました。

例では、 java.netAPIの基本的なServerSocketクラスと、JettyやTomcatなどの他の一般的なサーバー実装について説明しました。

いつものように、完全なソースコードはGitHubから入手できます。