1. 序章

このチュートリアルでは、Unixドメインソケットチャネルについて学習します。

いくつかの理論的な基本、長所、短所を取り上げ、Unixドメインソケットチャネルを使用してテキストメッセージを交換する単純なJavaクライアントサーバーアプリケーションを構築します。

また、データベースに接続するためにUnixドメインソケットを使用する方法についても見ていきます。

2. Unixドメインソケットチャネル

従来のプロセス間通信には、IPアドレスとポート番号で定義された TCP /IPソケットが含まれます。 これらは、インターネットまたはプライベートネットワークでのネットワーク通信に使用されます。

一方、Unixドメイン sockets は、同じ物理ホスト上のプロセス間の通信にのみ制限されます。 これらは何十年もの間Unixオペレーティングシステムの機能でしたが、最近MicrosoftWindowsに追加されました。 そのため、Unixシステムに限定されなくなりました。

Unixドメインソケットは、他のファイル名とほとんど同じに見えるファイルシステムパス名でアドレス指定されます。たとえば、 / folder / socketまたはC:\ folder \ socket 。 TCP / IP接続と比較すると、セットアップ時間が短縮され、出力を介したデータが多くなり、リモート接続を受け入れる際のセキュリティリスクがなくなります。 一方、最大の欠点は、単一の物理ホストのみに制限されることです。

共有ボリューム上にソケットを作成する限り、同じシステム上のcontainer間の通信にUnixドメインソケットを使用することもできることに注意してください。

3. ソケット構成

以前に学習したように、Unixドメインソケットはファイルシステムのパス名に基づいているため、最初に、ソケットファイルのパスを定義し、それをUnixDomainSocketAddressに変換する必要があります。

Path socketPath = Path
  .of(System.getProperty("user.home"))
  .resolve("baeldung.socket");
UnixDomainSocketAddress socketAddress = UnixDomainSocketAddress.of(socketPath);

この例では、baeldung.socketファイルの下のユーザーのホームディレクトリにソケットを作成します。

サーバーをシャットダウンするたびにソケットファイルを削除することを覚えておく必要があります。

Files.deleteIfExists(socketPath);

残念ながら、自動的に削除されることはなく、今後の接続に再利用することはできません。 同じパスを再利用しようとすると、このアドレスがすでに使用されているという例外が発生します。

java.net.BindException: Address already in use

4. メッセージの受信

次にできることは、ソケットチャネルからメッセージを受信するサーバーを起動することです。

まず、Unixプロトコルを使用してサーバーソケットチャネルを作成する必要があります。

ServerSocketChannel serverChannel = ServerSocketChannel
  .open(StandardProtocolFamily.UNIX);

さらに、以前に作成したソケットアドレスでバインドする必要があります。

serverChannel.bind(socketAddress);

これで、最初のクライアント接続を待つことができます。

SocketChannel channel = serverChannel.accept();

クライアントが接続すると、メッセージはバイトバッファに送られます。 これらのメッセージを読むには、入力を処理し、すべてのメッセージをコンソールに出力する無限ループを構築する必要があります。

while (true) {
    readSocketMessage(channel)
      .ifPresent(message -> System.out.printf("[Client message] %s", message));
    Thread.sleep(100);
}

上記の例では、メソッド readSocketMessage は、ソケットチャネルバッファーをString:に変換します。

private Optional<String> readSocketMessage(SocketChannel channel) throws IOException {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int bytesRead = channel.read(buffer);
    if (bytesRead < 0)
        return Optional.empty();

    byte[] bytes = new byte[bytesRead];
    buffer.flip();
    buffer.get(bytes);
    String message = new String(bytes);
    return Optional.of(message);
}

サーバーはクライアントの前に起動する必要があることを覚えておく必要があります。 この例のように、単一のクライアント接続のみを受け入れることができます。

5. メッセージの送信

メッセージの送信は、メッセージの受信よりも少し簡単です。

設定する必要があるのは、Unixプロトコルを使用したソケットチャネルとそれをソケットアドレスに接続することだけです。

SocketChannel channel = SocketChannel
  .open(StandardProtocolFamily.UNIX);
channel.connect(socketAddress);

これで、テキストメッセージを準備できます。

String message = "Hello from Baeldung Unix domain socket article";

それをバイトバッファに変換します:

ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.clear();
buffer.put(message.getBytes());
buffer.flip();

データ全体をソケットに書き込みます。

while (buffer.hasRemaining()) {
    channel.write(buffer);
}

最後に、次の出力がサーバーログに表示されます。

[Client message] Hello from Baeldung Unix domain socket article!

6. データベースへの接続

Unixドメインソケットを使用してデータベースに接続できます。 MongoDB やPostgreSQLなどの多くの一般的なディストリビューションには、すぐに使用できるデフォルト構成が付属しています。

たとえば、MongoDBは、 /tmp/mongodb-27017.sock にUnixドメインソケットを作成します。これは、MongoClient構成で直接使用できます。

MongoClient mongoClient = new MongoClient("/tmp/mongodb-27017.sock");

1つの要件は、jnr.unixsocket依存関係をプロジェクトに追加することです。

<dependency>
    <groupId>com.github.jnr</groupId>
    <artifactId>jnr-unixsocket</artifactId>
    <version>0.38.13</version>
</dependency>

一方、PostgreSQLでは、JDBC標準でUnixドメインソケットを使用することができます。 したがって、接続を作成するときに、追加のsocketFactoryパラメーターを指定する必要があります。

String dbUrl = "jdbc:postgresql://databaseName?socketFactory=org.newsclub.net.unix.
  AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/var/run/postgresql/.s.PGSQL.5432";
Connection connection = DriverManager
  .getConnection(dbUrl, "dbUsername", "dbPassword")

socketFactory パラメーターは、java.net.SocketFactoryを拡張するクラスを指している必要があります。 このクラスは、TCP/IPソケットの代わりにUnixドメインソケットを作成する役割を果たします。

この例では、junixsocketライブラリAFUNIXSocketFactoryクラスを使用しました。

<dependency>
  <groupId>com.kohlschutter.junixsocket</groupId>
  <artifactId>junixsocket-core</artifactId>
  <version>2.4.0</version>
</dependency>

7. 概要

このチュートリアルでは、Unixドメインソケットチャネルの使用方法を学びました。 Unixドメインソケットを使用したメッセージの送信と受信の両方について説明し、Unixドメインソケットを使用してデータベースに接続する方法を学習しました。 いつものように、すべてのソースコードはGitHub利用できます。