NIO摘錄

NIO,一種基於通道和緩衝區的I/O方式,可使用native函數庫直接分配堆外內存,而後經過一個存儲在javajava

堆的DirectBteBuffer對象做爲這塊內存的引用進行操做,避免了再java堆和native堆中來回複製數據。緩存

 

NIO是一種同步非阻塞的IO模型。同步是指線程不斷輪詢IO事件是否就緒,非阻塞指線程在等待IO的時候,能夠服務器

同時作其餘任務。同步的核心是Selector,Selector代替了線程自己輪詢IO事件,避免了阻塞同時減小了沒必要要的socket

線程消耗;非阻塞的核心就是通道和緩衝區,當IO事件就緒時,能夠經過寫道緩衝區,保證IO的成功,而無需線程ide

阻塞式地等待。函數

 

Bufferthis

爲何NIO是基於緩衝區的IO方式,由於當一個鏈接創建完成後,IO數據未必會立刻到達,爲了當數據達到時可以正確
spa

完成IO操做,在BIO(阻塞IO)中,等待IO的線程必須被阻塞,以全天候地進行IO操做。爲了解決這種IO方式的低效問題,.net

引入了緩衝區的概念,當數據達到時,能夠預先被寫入緩衝區,再由緩衝區交給線程,所以線程無需阻塞等待IO線程

 

通道

當執行:SocketChannel.write(Buffer),將一個buffer寫到一個通道中。通道來講相對比較抽象。通道是I/O傳輸發生時經過的入口

而緩衝區是這些數據傳輸的來源或目標。對於離開緩衝區的傳輸,你想傳遞出去的數據被置於一個緩衝區,被傳送到通道。對於

傳回緩衝區的傳輸,一個通道將數據放置於你所提供的緩衝區中。

 

例若有個服務器通道ServerSocketChannel serverChannel,一個客戶端通道SocketChannel clientChannel;服務器緩存區

serverBuffer,客戶端緩衝區clientBuffer。當服務器想向客戶端發送數據時,須要調用clientChannel.write(serverBuffer)。當

客戶端要讀時,調用clientChannel.read(clientBuffer);當客戶端向服務器發送數據時,須要調用serverChannel.write(clientBuffer)

當服務器要讀時,調用serverChannel.read(serverBuffer); 能夠理解爲在NIO中,若是想將data發送到目標端,則須要將存儲該

data的buffer,寫入到目標端channel中,而後再從channel中讀取數據到目標端的buffer中。

 

Selector

通道和緩衝區的機制,使得現場無需阻塞等待IO事件的就緒,但總的要有人來監管這些IO事件。 這就由selector來完成。selector容許

單個現場處理多個channel,若是你的應用打開了多個鏈接(通道),但每一個鏈接的流量都很低,使用selector就比較方便

 

要使用selector,的向selector註冊channel,而後調用它的select方法,這個方法會一直阻塞到某個註冊的通道有事件就緒,這就是輪詢。

一旦這個方法返回,線程就能夠處理這些事件。

 

selector中註冊的感興趣事件有: OP_ACCEPT  OP_CONNECT  OP_READ  OP_WRITE

 

簡單基於NIO方式實現server/client示例

package com.exe.learn.demo.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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class ServerNio {

    private Selector selector;
    
    public void initServer(int port) throws IOException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        //設置非阻塞模式
        serverChannel.configureBlocking(false);
        serverChannel.socket().bind(new InetSocketAddress(port));
        this.selector = Selector.open();
        //將selector註冊到服務端
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    }
    
    public void listen() throws IOException {
        System.out.println("服務端啓動》》》》》");
        while(true) {
            selector.select();
            Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();
            while(ite.hasNext()) {
                SelectionKey key = (SelectionKey) ite.next();
                ite.remove();
                if(key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.write(ByteBuffer.wrap(new String("來自服務端的信息").getBytes()));
                    socketChannel.register(this.selector, SelectionKey.OP_READ);
                }else if(key.isReadable()){
                    readFromClient(key);
                }
            }
        }
    }

    private void readFromClient(SelectionKey key) throws IOException {
        SocketChannel server = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(10);
        server.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("來自客戶端的信息" + msg);
        server.write(ByteBuffer.wrap(new String(msg).getBytes()));
    }
    
    public static void main(String[] args) throws IOException {
        ServerNio server = new ServerNio();
        server.initServer(1024);
        server.listen();
    }
}
View Code
package com.exe.learn.demo.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;

public class ClientNio {

    private Selector selector;

    public void initClient(String ip, int port) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        this.selector = Selector.open();
        //鏈接server端
        socketChannel.connect(new InetSocketAddress(ip, port));
        socketChannel.register(selector, SelectionKey.OP_CONNECT);
    }
    
    public void listen() throws IOException {
        System.out.println("客戶端啓動》》》》》》");
        while(true) {
            selector.select();
            Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();
            while(ite.hasNext()) {
                SelectionKey key = ite.next();
                ite.remove();
                if(key.isConnectable()) {
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    if(socketChannel.isConnectionPending()) {
                        socketChannel.finishConnect();
                    }
                    socketChannel.configureBlocking(false);
                    socketChannel.write(ByteBuffer.wrap(new String("向服務器發送信息了".getBytes(), "UTF-8").getBytes()));
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }else if(key.isReadable()) {
                    readFromServer(key);
                }
            }
        }
    }

    private void readFromServer(SelectionKey key) throws IOException {
        SocketChannel server = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(10);
        server.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("來自服務端的信息" + msg);
        server.write(ByteBuffer.wrap(new String(msg).getBytes()));
    }
    
    public static void main(String[] args) throws IOException {
        ClientNio client = new ClientNio();
        client.initClient("127.0.0.1", 1024);
        client.listen();
    }
}
View Code
相關文章
相關標籤/搜索