Java は 3 つのネットワーク プログラミング モデルをサポートします: BIO、NIO、AIO
NIO はバッファ指向、つまりブロック指向のプログラミングです。データはバッファに読み込まれ、後で処理されます。必要に応じてバッファ内でデータを前後に移動できるため、処理プロセスの柔軟性が向上します。 Use It は、ノンブロッキングで拡張性の高いネットワークを提供します。
HTTP2.0 は多重化テクノロジーを使用して、同じ接続で複数のリクエストを同時に処理できるようにしており、同時リクエストの数は HTTP1.1 よりも数桁多くなります。
つまり、NIO は 1 つのスレッドで複数のリクエストを処理できます。
フローチャートの説明:
バッファは本質的にデータの読み書きができるメモリ ブロックであり、コンテナ オブジェクト (配列を含む) として理解できます。メモリ ブロックの操作を容易にする一連のメソッドと、バッファ オブジェクトにはバッファの状態変化を追跡および記録するためのメカニズムが組み込まれています。 Channel はファイルやネットワークからデータを読み取るためのチャネルを提供しますが、読み書きされるデータは Buffer を経由する必要があります。
NIO では、Buffer は最上位の親クラスであり、抽象クラスです。
ByteBuffer、バイト データをバッファに格納します;
ShortBuffer、文字列データをバッファに保存します;
CharBuffer、文字データをバッファに保存します;
IntBuffer、整数データを保存しますバッファに保存;
LongBuffer、長整数データをバッファに保存;
DoubleBuffer、小数をバッファに保存;
FloatBuffer、バッファに小数を格納します;
#3. 共通バッファ API
##public Final int Capacity( )//このバッファの容量を返します
public Final int Position( )//このバッファの位置を返します
publicfinal Bufferposition (int newPositio)//このバッファの位置を設定します
public Final int limit( )//このバッファ Limit を返します
public Final Buffer limit (int newLimit)//このバッファの制限を設定します
public Final Buffer mark()// マークを設定しますこのバッファの位置
publicfinal Buffer replace()//このバッファの位置を以前にマークされた位置にリセットします
publicfinal Buffer clear( )//このバッファをクリアします。つまり、各マークを初期状態に戻しますが、データは実際には消去されず、後続の操作で上書きされます
public Final Bufferフリップ( )//このバッファを巻き戻します
public Final Buffer rewind( )//このバッファを巻き戻します
public Final int Remaining( )/ /現在位置と制限値の間の要素の数を返します
public Final boolean hasRemaining( )//現在位置と制限値の間に要素があるかどうかを通知します
public abstract boolean isReadOnly( );//このバッファが読み取り専用バッファかどうかを通知します
JDK1.6で導入されたAPI
public abstract boolean hasArray();//このバッファにアクセス可能な基になる実装があるかどうかを通知します。 array
public abstract Object array();/ /基になる実装を返します。このバッファの配列
1. 基本的な紹介
(4) 一般的に使用されるチャネル クラスには、FileChannel、DatagramChannel、ServerSocketChannel、および SocketChannel が含まれます。 ServerSocketChanne は ServerSocket に似ており、SocketChannel は Socket に似ています。
(5) FileChannel はファイルデータの読み書きに使用され、DatagramChannel は UDP データの読み書きに使用され、ServerSocketChannel と SocketChannel は TCP データの読み書きに使用されます。2. FileChannel
FileChannel は主にローカル ファイルで IO 操作を実行するために使用されます。一般的なメソッドは次のとおりです:
ByteBuffer は、型付きの put と get、put into データ型をサポートします。 get は、対応するデータ型を使用して取得する必要があります。そうでない場合は、BufferUnderflowException 例外が発生する可能性があります。
通常のバッファを読み取り専用バッファに変換できます。
NIO は、ファイルをメモリ (ヒープ外のメモリ) 内で直接変更できるようにする MappedByteBuffer も提供しており、ファイルの同期方法は NIO によって完了します。
NIO は、複数のバッファ (バッファ配列) を介した読み取りおよび書き込み操作、つまりスキャッタリングとギャザリングもサポートします。
Java の NIO を使用します。ノンブロッキングIOモード。 1 つのスレッドを使用して複数のクライアント接続を処理でき、セレクターを使用します。
Selector は登録されている複数のチャネルでイベントが発生したかどうかを検出し、イベントが発生した場合はイベントを取得し、それぞれのイベントに応じて処理します。このように、複数のチャネルの管理、つまり複数の接続とリクエストの管理に 1 つのスレッドのみを使用できます。
読み取りと書き込みは、接続/チャネル上に実際の読み取りおよび書き込みイベントがある場合にのみ発生するため、システムのオーバーヘッドが大幅に削減され、接続ごとにスレッドを作成する必要がなくなります。複数のスレッドを維持する必要があります。
複数のスレッド間のコンテキストの切り替えによって発生するオーバーヘッドを回避します。
package com.nezha.guor.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.*;import java.util.Iterator;public class NioServer { private Selector selector; private ServerSocketChannel serverSocketChannel; private static final int PORT = 8080; public NioServer() { try { //获得选择器 selector = Selector.open(); serverSocketChannel = ServerSocketChannel.open(); //绑定端口 serverSocketChannel.socket().bind(new InetSocketAddress(PORT)); //设置非阻塞模式 serverSocketChannel.configureBlocking(false); //将该ServerSocketChannel 注册到selector serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); }catch (IOException e) { System.out.println("NioServer error:"+e.getMessage()); } } public void listen() { System.out.println("监听线程启动: " + Thread.currentThread().getName()); try { while (true) { int count = selector.select(); if(count > 0) { //遍历得到selectionKey集合 Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); if(key.isAcceptable()) { SocketChannel sc = serverSocketChannel.accept(); sc.configureBlocking(false); sc.register(selector, SelectionKey.OP_READ); System.out.println(sc.getRemoteAddress() + " 上线 "); } //通道发送read事件,即通道是可读的状态 if(key.isReadable()) { getDataFromChannel(key); } //当前的key 删除,防止重复处理 iterator.remove(); } } else { System.out.println("等待中"); } } }catch (Exception e) { System.out.println("listen error:"+e.getMessage()); } } private void getDataFromChannel(SelectionKey key) { SocketChannel channel = null; try { channel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int count = channel.read(buffer); //根据count的值做处理 if(count > 0) { String msg = new String(buffer.array()); System.out.println("来自客户端: " + msg); //向其它的客户端转发消息(排除自己) sendInfoToOtherClients(msg, channel); } }catch (IOException e) { try { System.out.println(channel.getRemoteAddress() + " 离线了"); //取消注册 key.cancel(); }catch (IOException ex) { System.out.println("getDataFromChannel error:"+ex.getMessage()); } }finally { try { channel.close(); }catch (IOException ex) { System.out.println("channel.close() error:"+ex.getMessage()); } } } //转发消息给其它客户(通道) private void sendInfoToOtherClients(String msg, SocketChannel self ) throws IOException{ System.out.println("服务器转发消息中..."); System.out.println("服务器转发数据给客户端线程: " + Thread.currentThread().getName()); //遍历 所有注册到selector 上的 SocketChannel,并排除 self for(SelectionKey key: selector.keys()) { Channel targetChannel = key.channel(); //排除自己 if(targetChannel instanceof SocketChannel && targetChannel != self) { SocketChannel dest = (SocketChannel)targetChannel; //将信息存储到buffer ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes()); //将buffer数据写入通道 dest.write(buffer); } } } public static void main(String[] args) { //创建服务器对象 NioServer nioServer = new NioServer(); nioServer.listen(); }}
package com.nezha.guor.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Scanner;public class NioClient { private final int PORT = 8080; //服务器端口 private Selector selector; private SocketChannel socketChannel; private String username; public NioClient() throws IOException { selector = Selector.open(); socketChannel = socketChannel.open(new InetSocketAddress("127.0.0.1", PORT)); //设置非阻塞 socketChannel.configureBlocking(false); //将channel注册到selector socketChannel.register(selector, SelectionKey.OP_READ); username = socketChannel.getLocalAddress().toString().substring(1); System.out.println(username + " is ok..."); } //向服务器发送消息 public void sendInfo(String info) { info = username + " 说:" + info; try { socketChannel.write(ByteBuffer.wrap(info.getBytes())); }catch (IOException e) { System.out.println("sendInfo error:"+e.getMessage()); } } //读取从服务器端回复的消息 public void readInfo() { try { int readChannels = selector.select(); if(readChannels > 0) { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); if(key.isReadable()) { //得到相关的通道 SocketChannel sc = (SocketChannel) key.channel(); //得到一个Buffer ByteBuffer buffer = ByteBuffer.allocate(1024); //读取 sc.read(buffer); //把读到的缓冲区的数据转成字符串 String msg = new String(buffer.array()); System.out.println(msg.trim()); } } iterator.remove(); //删除当前的selectionKey, 防止重复操作 } else { System.out.println("没有可以用的通道..."); } }catch (Exception e) { System.out.println("readInfo error:"+e.getMessage()); } } public static void main(String[] args) throws Exception { NioClient nioClient = new NioClient(); new Thread() { public void run() { while (true) { nioClient.readInfo(); try { Thread.currentThread().sleep(2000); }catch (InterruptedException e) { System.out.println("sleep error:"+e.getMessage()); } } } }.start(); //发送数据给服务器端 Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()) { nioClient.sendInfo(scanner.nextLine()); } }}
以上がJava NIO サンプルの使用法と特性を分析するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。