java NIO學習筆記

#JAVA NIO

JAVA NIO的定義

IO大家都知道是Input 與Output的縮寫,而N是New的意思,java 1.4在不替換原有的IO實現的情況下,新增加一套IO機制,所以叫NIO,然後舊的叫OIO。

爲什麼學習Java NIO?

因爲高性能的通訊框架底層很多都用到了它,如果不學習它,導致在看那些框架的源碼看不懂,比如Netty,tomcat 7+等

它出現的目的

因爲java爲了實現write once run anywhere做出個JVM,通過Jvm屏蔽操作系統之間差異,帶來的好處很明顯,劣勢就是屏蔽太多系統之間的特點,比如一些操作系統所對IO的優勢,所以javaNIO就是解決OIO所存在的IO問題的,比如OIO會存在的就數據讀取是網卡讀取內核的空間,再拷貝到用戶空間,在NIO裏有直接支持零拷貝技術,所以Netty就是利用這一點實現壓榨服務器資源。

如下根據java NIO 實現聊天室的Server端代碼


public class ServerSocketWithNIO {

    private List<SocketChannel> socketChannels = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        new ServerSocketWithNIO().go(args);
    }
    public void go(String[] args) throws IOException {
    	//創建serverSocketChannel
        ServerSocketChannel serverSocketChannel =   = SelectorProvider.provider().open();
		
		//綁定端口
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocketChannel.configureBlocking(false);
        serverSocket.bind(new InetSocketAddress(Integer.parseInt(args[0])));

		//創建Selector
        Selector selector = Selector.open();
        //註冊感興趣事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
        	//獲取就緒事件個數
            int select = selector.select();
            if (select > 0) {
            	//獲取IO已就緒的selectedKeys
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    
                    //新連接進來,註冊讀事件
                    if (selectionKey.isAcceptable()) {
                        ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
                        SocketChannel socketChannel = channel.accept();
                        socketChannel.configureBlocking(false);
                        socketChannels.add(socketChannel);

                        socketChannel.register(selector, SelectionKey.OP_READ);
                        sayHello(socketChannel);
                    }

  					 //讀取數據
                    if (selectionKey.isReadable()) {
                        readDataFromChannel((SocketChannel) selectionKey.channel());
                    }
                    //處理完之前要從集合裏刪除
                    iterator.remove();
                }
            }
        }
    }

    private void readDataFromChannel(SocketChannel channel) throws IOException {
        ByteBuffer allocate = ByteBuffer.allocate(1024);
        while (channel.read(allocate) > 0) {
            allocate.flip();
            while (allocate.hasRemaining()) {
                //向所有的發送消息
                socketChannels.forEach(socketChannel -> {
                    if (socketChannel != channel) {
                        try {
                            socketChannel.write(allocate);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
            allocate.clear();
        }
    }
    private void sayHello(SocketChannel socketChannel) throws IOException {
        socketChannel.write(UTF_8.encode("歡迎來到嘿嘿聊天室!!!"));
    }
}

其中表涉及到四個概念buffer,channel,seletor,selectKey

其中 channel理解成一個連接通道,可能基於這個通道進行一系列的IO操作,如socket上的操作accept, read, write等

然後buffer可以理解成一個緩衝區,在channel讀取到的字節可以放到buffer裏存放然後讀取等;

selector可以根據字面的意思理解成一個選擇器,就是根據註冊到上面的channel列表選擇出可進行IO操作的Channel;

selectKey可以理解channel與selector之間的註冊關係

所以它的主要流程

  1. 創建channel
  2. 綁定端口
  3. 創建selector
  4. 把channel根據感興趣的事件註冊到selector
  5. 循環獲取selector返回IO就緒的channel列表,然後做相應的業務處理

其中這四個概念詳細學習可以下載java NIO,看完它會對java NIO有個整體的瞭解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章