天天看点

【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();
        }
    }
}