Java-nio-server-socket-channel

提供:Dev Guides
移動先:案内検索

Java NIO-ServerSocketチャネル

Java NIOサーバーソケットチャネルは、ソケットを接続するストリーム指向のデータフローに使用される選択可能なタイプのチャネルです。サーバーソケットチャネルは、静的* open()メソッドを呼び出して、既存のソケットがまだ存在しない場合に作成できます。チャネルはopenメソッドを呼び出して作成されますが、まだバインドされていません。バインドするには、ソケットチャネル bind()*メソッドを呼び出します。

ここで言及する1つのポイントは、チャネルがバインドされておらず、I/O操作が試行されると、このチャネルによってNotYetBoundExceptionがスローされるため、IO操作を実行する前にチャネルがバインドされていることを確認する必要があります。

サーバーソケットチャネルへの着信接続は、ServerSocketChannel.accept()メソッドを呼び出すことでリッスンします。 accept()メソッドが戻ると、着信接続とともにSocketChannelを返します。 したがって、accept()メソッドは、着信接続が到着するまでブロックします。チャネルが非ブロッキングモードの場合、acceptメソッドは保留中の接続がない場合、すぐにnullを返します。 それ以外の場合は、新しい接続が利用可能になるか、またはI/Oエラーが発生するまで無期限にブロックされます。

新しいチャネルのソケットは、最初はバインドされていません。接続を受け入れる前に、ソケットのバインドメソッドの1つを介して特定のアドレスにバインドする必要があります。また、システム全体のデフォルトのSelectorProviderオブジェクトのopenServerSocketChannelメソッドを呼び出すことにより、新しいチャネルが作成されます。

ソケットチャネルサーバーのように、ソケットチャネルは* read()*メソッドを使用してデータを読み取ることができます。最初にバッファが割り当てられます。 ServerSocketChannelから読み取られたデータはバッファーに格納されます。次に、ServerSocketChannel.read()メソッドを呼び出し、ServerSocketChannelからバッファーにデータを読み取ります。 read()メソッドの整数値は、バッファーに書き込まれたバイト数を返します

同様に、バッファとしてパラメーターを使用する* write()*メソッドを使用して、サーバーソケットチャネルにデータを書き込むことができます。一般的に、バッファーに書き込み可能なバイトがなくなるまで、write()メソッドを繰り返す必要があるwhileループでwriteメソッドを使用します。

ソケットチャネルの重要なメソッド

  • * bind(SocketAddress local)*-このメソッドは、このメソッドのパラメーターとして提供されるローカルアドレスにソケットチャネルをバインドするために使用されます。
  • * accept()*-このメソッドは、このチャネルのソケットへの接続を受け入れるために使用されます。
  • * connect(SocketAddress remote)*-このメソッドは、ソケットをリモートアドレスに接続するために使用されます。
  • * finishConnect()*-このメソッドは、ソケットチャネルの接続プロセスを終了するために使用されます。
  • * getRemoteAddress()*-このメソッドは、チャネルのソケットが接続されているリモートロケーションのアドレスを返します。
  • * isConnected()*-すでに述べたように、このメソッドはソケットチャネルの接続状態、つまり接続されているかどうかを返します。
  • * open()*-Openメソッドを使用して、指定されたアドレスのないソケットチャネルを開きます。この便利なメソッドは、open()メソッドを呼び出し、結果のサーバーソケットチャネルでconnectメソッドを呼び出し、リモートに渡し、そのチャンネルを返します。
  • * read(ByteBuffer dst)*-このメソッドは、ソケットチャネルを介して指定されたバッファからデータを読み取るために使用されます。
  • * setOption(SocketOption <T> name、T value)*-このメソッドは、ソケットオプションの値を設定します。
  • * socket()*-このメソッドは、このチャネルに関連付けられたサーバーソケットを取得します。
  • * validOps()*-このメソッドは、このチャネルのサポートされる操作を識別する操作セットを返します。サーバーソケットチャネルは、新しい接続の受け入れのみをサポートするため、このメソッドはSelectionKey.OP_ACCEPTを返します。

次の例は、Java NIO ServerSocketChannelからデータを送信する方法を示しています。

C:/Test/temp.txt

Hello World!

クライアント:SocketChannelClient.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;

public class SocketChannelClient {
   public static void main(String[] args) throws IOException {
      ServerSocketChannel serverSocket = null;
      SocketChannel client = null;
      serverSocket = ServerSocketChannel.open();
      serverSocket.socket().bind(new InetSocketAddress(9000));
      client = serverSocket.accept();
      System.out.println("Connection Set:  " + client.getRemoteAddress());
      Path path = Paths.get("C:/Test/temp1.txt");
      FileChannel fileChannel = FileChannel.open(path,
         EnumSet.of(StandardOpenOption.CREATE,
            StandardOpenOption.TRUNCATE_EXISTING,
            StandardOpenOption.WRITE)
         );
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(client.read(buffer) > 0) {
         buffer.flip();
         fileChannel.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Received");
      client.close();
   }
}

出力

クライアントを実行しても、サーバーが起動するまで何も出力されません。

サーバー:SocketChannelServer.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;

public class SocketChannelServer {
   public static void main(String[] args) throws IOException {
      SocketChannel server = SocketChannel.open();
      SocketAddress socketAddr = new InetSocketAddress("localhost", 9000);
      server.connect(socketAddr);
      Path path = Paths.get("C:/Test/temp.txt");
      FileChannel fileChannel = FileChannel.open(path);
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(fileChannel.read(buffer) > 0) {
         buffer.flip();
         server.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Sent");
      server.close();
   }
}

出力

サーバーを実行すると、次が出力されます。

Connection Set: /127.0.0.1:49558
File Received