1. 程式人生 > >NIO 阻塞IO與非阻塞IO

NIO 阻塞IO與非阻塞IO

客戶端


        final SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));
        final FileChannel inChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\1.png"), StandardOpenOption.READ);
        final ByteBuffer buf = ByteBuffer.allocate(1024);
        while(inChannel.read(buf) != -1){
            buf.flip();
            sChannel.write(buf);
            buf.clear();
        }
        sChannel.shutdownOutput();
//        接收服務端的反饋
        int len = 0;
        while ((len = sChannel.read(buf)) != -1){
            buf.flip();
            System.out.println(new String(buf.array(), 0, len));
            buf.clear();
        }
        inChannel.close();
        sChannel.close();

服務端


        final ServerSocketChannel ssChannel = ServerSocketChannel.open();
        final FileChannel outChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\12.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        ssChannel.bind(new InetSocketAddress(8888));
        final SocketChannel sChannel = ssChannel.accept();
        final ByteBuffer buf = ByteBuffer.allocate(1024);
        while (sChannel.read(buf) != -1){
            buf.flip();
            outChannel.write(buf);
            buf.clear();
        }
//        傳送反饋給客戶端
        buf.put("服務端接受資料成功".getBytes());
        buf.flip();
        sChannel.write(buf);
        sChannel.close();
        outChannel.close();
        ssChannel.close();

非阻塞IO


非阻塞IO模式
通道註冊到選擇器, 選擇器監控通道的狀況, 如果當某一個通道上每一個請求的事件完全準備就緒時,選擇器才會將這個任務分配到服務端的一個或多個執行緒上再去執行

客戶端


//        1.獲取通道
        final SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));
//        切換非阻塞模式
        sChannel.configureBlocking(false);
//        分配指定大小的緩衝區
        final ByteBuffer buf = ByteBuffer.allocate(1024);
//        傳送資料給服務端
        buf.put(new Date().toString().getBytes());
        buf.flip();
        sChannel.write(buf);
        buf.clear();
        sChannel.close();

服務端


//        獲取通道
        final ServerSocketChannel ssChannel = ServerSocketChannel.open();
//        切換非阻塞模式
        ssChannel.configureBlocking(false);
//        繫結連線
        ssChannel.bind(new InetSocketAddress(8888));
//        獲取選擇器
        final Selector selector = Selector.open();
//        將通道註冊到選擇器上, 並指定監聽接收事件
        ssChannel.register(selector, SelectionKey.OP_ACCEPT);
//        輪詢式獲取選擇器上寂靜“準備就緒”的事件
        while (selector.select() > 0){
//            獲取當前選擇器中所有註冊的選擇鍵(已就緒的監聽事件)
            final Iterator<SelectionKey> it = selector.selectedKeys().iterator();
           while (it.hasNext()){
//              獲取準備就緒的事件
               final SelectionKey sk = it.next();
//               判斷是什事件準備就緒
               if(sk.isAcceptable()){
//                   若接收就緒,獲取客戶端連線
                   final SocketChannel sChannel = ssChannel.accept();
//                   謝歡非阻塞模式
                   sChannel.configureBlocking(false);
//                   將該通道註冊到選擇器上
                   sChannel.register(selector, SelectionKey.OP_READ);
               }else if(sk.isReadable()){
//                   獲取當前選擇器上讀就緒狀態的通道
                   final SocketChannel sChannel = (SocketChannel) sk.channel();
//                   讀取資料
                   final ByteBuffer buf = ByteBuffer.allocate(1024);
                   int len = 0;
                   while ((len = sChannel.read(buf)) > 0){
                       buf.flip();
                       System.out.println(new String(buf.array(), 0, len));
                       buf.clear();
                   }

               }
//               取消選擇鍵
               it.remove();
           }