Java でノンブロッキング I/O を使用する方法

黄舟
リリース: 2017-09-29 09:58:37
オリジナル
1533 人が閲覧しました

この記事では主に Java でノンブロッキング I/O を使用する方法について説明します。また、ノンブロッキング I/O を使用してクライアントを実装する方法も示します。必要な場合はそれを参照できます。

ほとんどの知識と例は、O'REILLY の『Java Network Programming, Fourth Edition, by Elliotte Rusty Harold (O'REILLY)』から得ています。

ノンブロッキング I/O の概要

ノンブロッキング I/O (NIO) は、高い同時実行性を処理する手段です。同時実行性が高い場合、スレッドの作成とリサイクル、およびスレッド間の切り替えのオーバーヘッドが無視できなくなります。このとき、ノンブロッキング I/O テクノロジを使用できます。このテクノロジーの中心となるアイデアは、準備された接続を一度に選択し、その接続で管理できる限り多くのデータをできるだけ早く埋めてから、次の準備された接続に移動することです。

ノンブロッキングI/Oを使用して実装されたクライアント

通常、クライアントは多数の同時接続を処理する必要はありません。実際、ノンブロッキング I/O は主にサーバー向けに設計されていますが、クライアントでも使用できます。クライアントの設計はサーバーの設計よりも簡単であるため、以下の簡単なデモではクライアントを使用します。

まずchannelとバッファを紹介します。 SocketChannel クラスは、ノンブロッキング I/O で接続を作成するために使用されます。 SocketChannel オブジェクトを取得するには、SocketAddress オブジェクト (通常はそのサブクラス InetSocketAddress) をその静的ファクトリ メソッド open() に渡す必要があります。以下に例を示します。


SocketAddress address = new InetSocketAddress("127.0.0.1", 19);
SocketChannel client = SocketChannel.open(address);
ログイン後にコピー

open() メソッドはブロックしているため、これ以降のコードは接続が確立されるまで実行されません。接続を確立できない場合は、IOException がスローされます。

接続が確立されたら、入力と出力を取得する必要があります。従来の getInputStream() や getOutputStream() とは異なり、チャネルを使用すると、チャネル自体に直接書き込むことができます。バイト配列に書き込む代わりに、ByteBuffer オブジェクトが書き込まれます。 ByteBuffer オブジェクトは ByteBuffer.allocate(int Capacity) によって取得されます。Capacity はバイト単位のバッファ サイズです。ソケットから読み取られたデータがこのバッファに格納されます。 read() メソッドは、正常に読み取られてバッファに保存されたバイト数を返します。デフォルトでは、少なくとも 1 バイトを読み取るか、データの終わりを示す -1 を返し、使用可能なバイトがない場合はブロックします。これは、InputStream とほぼ同じように動作します。ただし、ノンブロッキング モードに設定されている場合、使用可能なバイトがない場合はすぐに 0 が返され、ブロックされません。


ここで、バッファー内に既にデータがあり、後でそれを抽出する必要があると仮定します。従来の方法を使用して、最初にデータをバイト配列に書き込み、次にそれを出力ストリームに書き込むことができます。これは完全にチャネルベースのメソッドです。Channels ツール クラスを使用して、出力ストリームをチャネルにカプセル化します。


ByteBuffer buffer = ByteBuffer.allocate(74);
ログイン後にコピー

上記のコードは、System.out をチャネルにカプセル化します。この後、出力を行うことができます。 ByteBuffer オブジェクトの各出力の前に、チャネルが最初から読み取りを開始できるように、その flip() メソッドを呼び出す必要があります。読み取りと書き込みの後、clear() メソッドを呼び出してバッファのステータスをリセットする必要があります。データ出力のコードは次のとおりです:


WritableByteChannel out = Channels.newChannel(System.out);
ログイン後にコピー

例 1: ノンブロッキング I/O を使用して実装された CharGenerator (文字ジェネレーター) クライアント


サーバー コード:

buffer.flip();
out.write(buffer);
buffer.clear();
ログイン後にコピー

クライアント コード:


public static void createCharGeneratorServer(){
  try(ServerSocket server = new ServerSocket(19)){
    while(true){
      try(Socket connection = server.accept()){
        OutputStream out = connection.getOutputStream();
        int firstPrintableCharacter = 33;
        int numberOfPrintableCharacter = 94;
        int numberOfCharactersPerLine = 72;
        int start = firstPrintableCharacter;
        while(true){
          for(int i = start ;
              i < start + numberOfCharactersPerLine ; i++){
            out.write
            (firstPrintableCharacter + (i - firstPrintableCharacter) % numberOfPrintableCharacter);
          }
          out.write(&#39;\r&#39;);
          out.write(&#39;\n&#39;);
          start = firstPrintableCharacter + (start + 1 - firstPrintableCharacter) % numberOfPrintableCharacter;
        }
      }catch (IOException e) {
        e.printStackTrace();
      }
    }
  } catch (IOException e) {
    e.printStackTrace();
  }
}
ログイン後にコピー

ノンブロッキングモードを有効にする


上記のプログラムは、入出力ストリームを使用する従来の方法とあまり変わりません。ただし、ServerSocket の configureBlocking(false) メソッドを呼び出して非ブロッキング モードに設定することができます。このモードでは、利用可能なデータがない場合、read() メソッドはすぐに戻り、クライアントは他のことを行うことができます。ただし、データを読み取れない場合、read() メソッドは 0 を返すため、データを読み取るループにいくつかの変更を加える必要があります。

以上がJava でノンブロッキング I/O を使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート