この記事では、java に関する関連知識を提供します。主に、NIO コア、BIO と NIO の比較、NIO ターミナル通信を介した単純なサーバー クライアントの実装など、NIO 関連の問題を紹介します。みんなの役に立つでしょう。
推奨学習: 「java チュートリアル 」
1. Java マインド マップ##2. I/O モデル
HTTP2.0 は多重化テクノロジーを使用して、同じ接続で複数のリクエストを同時に処理できるようにしており、同時リクエストの数は HTTP1.1 よりも数桁多くなります。
つまり、NIO は 1 つのスレッドで複数のリクエストを処理できます。
6. BIO と NIO の比較
フローチャートの説明:
チャネルは双方向であり、Linux などの基礎となるオペレーティング システムのステータスを返すことができます。基礎となるオペレーティング システム チャネルは双方向です。
バッファは本質的に、データの読み書きができるメモリ ブロックです。コンテナ オブジェクト (配列を含む) として理解できます。このオブジェクトは、使いやすくするためのメソッドのセットを提供します。バッファ オブジェクトには、バッファのステータス変化を追跡および記録できるいくつかの組み込みメカニズムがあります。 Channel はファイルやネットワークからデータを読み取るためのチャネルを提供しますが、読み書きされるデータは Buffer を経由する必要があります。
NIO では、Buffer は最上位の親クラスであり、抽象クラスです。
ByteBuffer、バイト データをバッファに格納します;
ShortBuffer、文字列データをバッファに保存します;
CharBuffer、文字データをバッファに保存します;
IntBuffer、整数データを保存しますバッファに保存;
LongBuffer、長整数データをバッファに保存;
DoubleBuffer、小数をバッファに保存;
FloatBuffer、バッファに小数を格納します;
#3. 共通バッファ API
public abstract Object array();//このバッファの基礎となる実装配列を返します
1 . 基本的な紹介
(1) NIO チャネルはストリームに似ています
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(); }}</selectionkey>
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()); } }}</selectionkey>
## 推奨学習: 「
>>」
以上がJava NIO を完全にマスターできるようにします (概要の共有)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。