Netty源碼02-Java的NIO(二)

Channel 通道

通道表示到實體(如硬件設備、文件、網絡套接字或程序組件)的開放鏈接,該實體可以執行一個或多個不一樣的I/O操做,例如讀取或寫入java

FileChannel

  • 用於讀取、寫入、映射和操做文件的通道
  • 文件通道是鏈接到文件的SeekableByteChannel。它在其文件中有一個當前的position,能夠是查詢position,也能夠是修改的position(long)。文件自己包含一個可變長度的字節序列,能夠讀取和寫入,而且能夠查詢當前的size。當寫入的字節超過當前大小時,文件大小會增長;當文件truncated時,文件大小會減少。文件還可能具備一些關聯的元數據,例如訪問權限、內容類型和上次修改時間;此類不定義元數據訪問的方法。

FileChannel的類繼承關係:

FileChannel.png

  • FileChannel的讀寫分離體現了接口的隔離原則
  • FileChannel中的read函數根據直接或非直接ByteBuffer讀取到堆緩衝區或者直接返回buffer緩衝區

SocketChannel

  • 網絡套接字Socket和上面文件是同樣的,在Linux上都抽象成了文件描述符fd
  • SocketChannel面向流的鏈接套接字的可選通道
  • 經過調用此類的open方法建立套接字通道。沒法爲任意的、預先存在的套接字建立通道。新建立的套接字通道已打開,但還沒有鏈接。試圖在未鏈接的通道上調用I/O操做將致使引起NotYetConnectedException。套接字通道能夠經過調用其connect方法進行鏈接;一旦鏈接,套接字通道將保持鏈接,直到關閉。套接字通道是否鏈接能夠經過調用其isConnected方法來肯定
  • SocketChannel支持無阻塞鏈接

SocketChannel的類繼承關係:

SocketChannel.png

Selector

Selector介紹

  • SelectorSelectableChannel對象的多路複用選擇器
  • 能夠經過調用此類的open方法來建立選擇器,該方法將使用系統默認的java.nio.channels.spi.SelectorProvider選擇器來建立新的選擇器。還能夠經過調用自定義選擇器java.nio.channels.spi.SelectorProvider.openSelector方法來建立選擇器。選擇器保持打開狀態,直到經過其close方法關閉爲止
  • SelectableChannel註冊Selector,並選擇感興趣的SelectionKeySelector維護三組SelectionKey網絡

    • key set:包含表示此選擇器當前Channel註冊的全部key。此集合由keys()方法返回
    • selected-key set:是一組鍵,用來存放在一個selection期間,那些以前註冊了感興趣的SelectionKeyChannel已準備好能夠操做的key的集合。此集合由selectedKeys()方法返回。selected-key set始終是ket set的子集
    • cancelled-key set:是已取消但其Channel還沒有註銷的鍵集。此集合不能直接訪問。cancelled-key set始終是ket set的子集
ServerSocketChannel ssc = ServerSocketChannel.open();
   ssc.register(selector, SelectionKey.OP_ACCEPT);

image.png

使用SelectionKey的注意點

  • SelectionKey返回的集合在Handler響應的Key事件以後,須要將Key顯式的刪除,否在下一次select的時候,這個Key還在,並且刪除須要用key的iterator進行刪除,不然將會拋出異常(Java SE基礎知識,容器刪除元素後容器大小變化形成

使用Selector的Java NIO示例代碼

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.socket().bind(new InetSocketAddress("127.0.0.1", 8888));
        ssc.configureBlocking(false);

        System.out.println("server started, listening on :" + ssc.getLocalAddress());
        Selector selector = Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT);

        while(true) {
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> it = keys.iterator();
            while(it.hasNext()) {
                SelectionKey key = it.next();
                it.remove();
                handle(key);
            }
        }

    }

    private static void handle(SelectionKey key) {
        if(key.isAcceptable()) {
            try {
                ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                SocketChannel sc = ssc.accept();
                sc.configureBlocking(false);
                //new Client
                //
                //String hostIP = ((InetSocketAddress)sc.getRemoteAddress()).getHostString();

            /*
            log.info("client " + hostIP + " trying  to connect");
            for(int i=0; i<clients.size(); i++) {
                String clientHostIP = clients.get(i).clientAddress.getHostString();
                if(hostIP.equals(clientHostIP)) {
                    log.info("this client has already connected! is he alvie " + clients.get(i).live);
                    sc.close();
                    return;
                }
            }*/

                sc.register(key.selector(), SelectionKey.OP_READ );
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
        } else if (key.isReadable()) { //flip
            SocketChannel sc = null;
            try {
                sc = (SocketChannel)key.channel();
                ByteBuffer buffer = ByteBuffer.allocate(512);
                buffer.clear();
                int len = sc.read(buffer);

                if(len != -1) {
                    System.out.println(new String(buffer.array(), 0, len));
                }

                ByteBuffer bufferToWrite = ByteBuffer.wrap("HelloClient".getBytes());
                sc.write(bufferToWrite);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(sc != null) {
                    try {
                        sc.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
相關文章
相關標籤/搜索