天天看點

【Java NIO】之 NonBlockingNIO

下面以一個執行個體介紹 NonBlockingNIO 的用法

/**
 * 一、使用 NIO 完成網絡通信的三個核心:
 *
 * 1. 通道(Channel):負責連接配接
 *
 * 	   java.nio.channels.Channel 接口:
 * 			|--SelectableChannel
 * 				|--SocketChannel
 * 				|--ServerSocketChannel
 * 				|--DatagramChannel
 *
 * 				|--Pipe.SinkChannel
 * 				|--Pipe.SourceChannel
 *
 * 2. 緩沖區(Buffer):負責資料的存取
 *
 * 3. 選擇器(Selector):是 SelectableChannel 的多路複用器。用于監控 SelectableChannel 的 IO 狀況
 *
 */
public class TestNonBlockingNIO {

    // 用戶端
    public static void main(String[] args)  throws IOException {
        // 1、擷取通道
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8989));

        // 2、切換為非阻塞模式
        sChannel.configureBlocking(false);

        // 3、配置設定緩沖區
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        // 4、發送資料給服務端
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String next = scanner.next();
            buffer.put((new Date() + "\n" + next).getBytes());
            buffer.flip();
            sChannel.write(buffer);
            buffer.clear();
        }

        // 5、關閉通道
        scanner.close();
    }

    // 服務端
    @Test
    public void server() throws IOException {
        // 1、擷取通道
        ServerSocketChannel ssChannel = ServerSocketChannel.open();

        // 2、切換非阻塞模式
        ssChannel.configureBlocking(false);

        // 3、綁定連接配接
        ssChannel.bind(new InetSocketAddress(8989));

        // 4、擷取選擇器
        Selector selector = Selector.open();

        // 5、将通道注冊到選擇器上,并指定"監聽接收事件"
        ssChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 6、輪詢式的擷取選擇器上已經"準備就緒"的事件
        while (selector.select() > 0) {
            // 7、擷取目前選擇器中所有已就緒的監聽事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            while (iterator.hasNext()) {
                // 8、擷取準備就緒的事件
                SelectionKey key = iterator.next();

                // 9、判斷具體是什麼事件準備就緒
                if (key.isAcceptable()) {
                    // 如果就緒事件為"接收就緒",則擷取用戶端連接配接
                    SocketChannel sChannel = ssChannel.accept();
                    // 設定為非阻塞模式
                    sChannel.configureBlocking(false);
                    // 同時把通道注冊到選擇器上
                    sChannel.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    // 擷取目前選擇器上“讀就緒”狀态的通道
                    SocketChannel sChannel = (SocketChannel) key.channel();
                    // 讀取用戶端資料
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int len = 0;
                    while ((len = sChannel.read(buffer)) > 0) {
                        buffer.flip();
                        System.out.println(">>> " + new String(buffer.array(), 0, len));
                        buffer.clear();
                    }
                }
                // 10、移除已經使用的選擇鍵
                iterator.remove();
            }
        }
    }
}

           

下面的執行個體為資料報版本

/**
 * 測試資料報的非阻塞通道
 */
public class TestNonBlockingNIO2 {

    // 發送端
    public static void main(String[] args) throws IOException {
        DatagramChannel sendChannel = DatagramChannel.open();

        sendChannel.configureBlocking(false);

        Scanner scanner = new Scanner(System.in);

        ByteBuffer buffer = ByteBuffer.allocate(1024);

        InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8899);

        while (scanner.hasNext()) {
            String data = scanner.next();
            buffer.put((new Date() + "\n" + data).getBytes());
            buffer.flip();
            sendChannel.send(buffer, socketAddress);
            buffer.clear();
        }

        sendChannel.close();
    }

    // 接收端
    @Test
    public void receiver() throws IOException{
        DatagramChannel recvChannel = DatagramChannel.open();

        recvChannel.configureBlocking(false);

        recvChannel.bind(new InetSocketAddress(8899));

        Selector selector = Selector.open();

        recvChannel.register(selector, SelectionKey.OP_READ);

        while (selector.select() > 0) {
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();

                if (key.isReadable()) {
                    ByteBuffer buffer = ByteBuffer.allocate(1024);

                    recvChannel.receive(buffer);
                    buffer.flip();
                    System.out.println(">>> " + new String(buffer.array(), 0, buffer.limit()));
                    buffer.clear();
                }
            }
            iterator.remove();
        }
    }
}