JAVA NIO概述

NIO

java 1.4版本引入,給予緩衝區面 向通道的io操做java

bio nio
面向流 面向緩衝區(buffer)
阻塞io 非阻塞io
同步 同步
Selector(選擇器)

緩衝區:是一個特定數據類型的容器,有java.nio 包定義,全部的緩衝區都是Buffer抽象類的子類
 子類:ByteBuffer  CharBuffer  ShortBuffer  IntBuffer LongBuffer FloatBuffer DoubleBuffer
 
 Buffer主要用於和NIO通道進行通訊,數據從通道讀入到緩衝區,再從緩衝區讀取到通道
 
 Buffer就像是一個數據能夠保存多個類型相同的數據
 
 基本屬性:
 1.容量(capacity):表示緩衝區的最大容量 一旦建立不能修改
 2.限制(limit):第一個不可讀的索引,即位於limit後面的數據不可讀
 3.位置(position):下一個要讀取或寫入數據的索引
 4.flip:將此時的position設爲limit,position置爲0 - 通常是從inputChannel將數據讀入到buffer 而後將buffer flip後 爲了從buffer中讀取數據到 outputChannel 
 5.標記(mark)和恢復(reset):標記是一個索引,經過Buffer.mark()指定一個特定的位置,使用reset方法能夠恢復到這個位置
  • 直接緩衝區:程序直接操做物理映射文件
  • 非直接緩衝區:jvm - 操做系統 - 物理內存

Channel:相似於流,可是Channel不能直接訪問數據,只能與緩衝區進行交互通道

 主體實現類
 1.FileChannel:用於讀取 寫入 映射和操做文件的通道
 2.DataGramChannel:經過UDP讀取網絡中的數據通道
 3.SocketChannel:經過Tcp讀寫通道的數據
 4.ServerSocketChannel:能夠監聽新進入的Tcp鏈接,對每個新鏈接建立一個SocketChannel
 
 提供getChannel()方法的類
 1.FileInputStream 2.FileOutputStream 3.RandomAccessFile 4.Socket 5.ServerSocket 6.DataGramSocket
 
 通道時間傳輸
 1.transferFrom() 2.transferTo()
  • 分散讀取(Scatter):將一個Channel 中的數據分散儲存到多個Buffer
  • 彙集寫入(Gather):將多個Buffer中的數據寫入同一個Channel

Selector通常被稱爲選擇器,也被稱爲多路複用器.用於檢查一個或多個通道是否處於可讀可寫如此能夠實現一個線程管理多個Channel
 
 使用Selector帶來的好處有:使用更少的線程來處理Channel,能夠防止上下文切換帶來的性能小號
 
 能夠被選擇(多路複用)的Channel都繼承自SelectableChannel
 
                             SelectableChannel 
                                    || 
                        AbstractSelectableChannel 
                      ||           ||            || 
            DataGramChannel SocketChannel ServerSocketChannel 
 
 因此FileChannel不適應與Selector,即不能切換爲非阻塞模式
 Selector使用基本步驟
 1.建立Selector: Selector selector = Selector.open();
 2.設置爲非阻塞爲:channel.configureBlocking(false); 
 3.註冊Channel到Selector:
 /** 
 * 參數-1:要註冊到的多路複用器
 * 參數-2:是一個"interest集合",即要監聽事件的集合(有如下四種)
 * OP_CONNECT 鏈接    
 * OP_ACEEPT 接收
 * OP_READ 讀
 * OP_WRITE 寫
 */ 
 SelectionKey key = channel.register(selector,SelectionKey.OP_READ); 
 若是要監聽多種事件以下:
 SelectionKey key = channel.register(selector,SelectionKey.OP_CONNECT | SelectionKey.OP_READ);    
 
 4.而後就 鏈接就緒 | 接收就緒 | 讀就緒 | 寫就緒

Selector主要方法

方法 描述
Set<SelectKey> keys() 返回全部SelectionKey集合,表明 註冊在這個Selector上Channel
Set<SelectKey> selectedKeys() 返回已選擇了的(即有io操做的)SelectionKey
int select() 監控全部註冊了的Channel,若是有須要 io的操做時會將對應的selectKey加入到 selectedKeys集合中,返回的則是被選擇 (有io操做的)Channel數量,這個操做時阻 塞的即只有被選擇的Channel數量>=1才 返回
int select(timeout) 有超時時長,一直沒有io操做的Channel出現, 到達timeout出現的時間後將自動返回
int selectNow() 無阻塞 當即返回
Selector wakeUp() 使正在select()當即返回
void close() 關閉

SelectionKey主要方法

SelectionKey表示ChannelSelector之間的關係,ChannelSelector註冊就會產生一個SelectionKey緩存

方法 描述
int interestOps() 感興趣事件的集合 boolean isInterested = interestSet & SelectionKey.OP_CONNECT ...
int readyOps() 獲取通道準備好就緒的操做
SelectableChannel channel() 獲取註冊通道
Selector selector() 獲取選擇器
boolean isConnectable() 檢測Channel中是否有鏈接事件就緒
boolean isAcceptable() 檢測Channel中是否有接收事件就緒
boolean isReadaable() 檢測Channel中是否有讀事件就緒
boolean isWriteable() 檢測Channel中是否有寫事件就緒
Object attach() 將一個對象附着到SelectionKey上, 主要是一些用於標識的信息
Object attachment() 獲取註冊信息 也能夠在Channel註冊的時候附着信息 SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject);
void cancel() 請求取消此鍵的通道到其選擇器的註冊
package com.yuan.nio.selector;
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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class NioServer {
    public static void main(String[] args) throws IOException {
         //建立服務端通道
         ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
         //非阻塞模式
         serverSocketChannel.configureBlocking(false);
         //綁定端口
         serverSocketChannel.bind(new InetSocketAddress(9021));
         //建立選擇器
         Selector selector = Selector.open();
         //註冊 接收
         serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
         //有一個事件時就操做
         while (selector.select() > 0) {
            //獲取事件集合
             Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
             while (iterator.hasNext()) {
                 SelectionKey selectionKey = iterator.next();
                 //若是是接收就緒
                 if (selectionKey.isAcceptable()) {
                     //獲取客戶端鏈接
                     SocketChannel socketChannel = serverSocketChannel.accept();
                     //切換成非阻塞
                     socketChannel.configureBlocking(false);
                     //註冊在多路複用器上 讀
                     socketChannel.register(selector, SelectionKey.OP_READ);
                     //讀事件
                  } else if (selectionKey.isReadable()) {
                        //獲取客戶端鏈接
                         SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                         //設置緩存
                         ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                         int len = 0;
                         while (-1 != (len = socketChannel.read(byteBuffer))) {
                                 byteBuffer.flip();
                                 System.out.println(new String(byteBuffer.array(),0,len));
                                 byteBuffer.clear();
                         }
                        //請求取消此鍵的通道在其選擇器的註冊,也就是 selector.select();的數量 -1 selectionKey.cancel();
                        socketChannel.close();
                    }
              }
              iterator.remove();
         }
    }
}
相關文章
相關標籤/搜索