Java NIO工作原理

数据通信流程:
通过selector.select()阻塞方法获取到感兴趣事件的key,根据key定位到channel,通过channel的读写操作进行数据通信。channel的read或者write操作都是通过buffer进行的。

代码示例

Server:

public class Server {
    public static void main(String[] args) throws InterruptedException {
        final int port = 9999;
        try {
            // 初始化server
            ServerSocketChannel server = ServerSocketChannel.open();
            server.socket().bind(new InetSocketAddress(port));
            Selector selector = Selector.open();

            // 这一步的设置在register中需要用到,所以要在register之前设置,否则会发生异常
            server.configureBlocking(false);
            SelectionKey serverKey = server.register(selector, SelectionKey.OP_ACCEPT);


            ByteBuffer buffer = ByteBuffer.allocate(50);
            // 事件循环
            while(true) {
                Thread.sleep(500);
                selector.select();
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = keys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    if (!key.isValid()) {
                        continue;
                    }
                    if (key.isAcceptable()) {
                        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                        SocketChannel sc = ssc.accept();
                        sc.configureBlocking(false);
                        sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
//                        System.out.println(serverKey == key);
                        continue;
                    }
                    if (key.isReadable()) {
                        SocketChannel sc = (SocketChannel) key.channel();
                        sc.read(buffer);
                        buffer.flip();
                        System.out.println(new String(buffer.array(), 0, buffer.limit()));
                    }
                    if (key.isWritable()) {
                        SocketChannel sc = (SocketChannel) key.channel();
                        sc.write(ByteBuffer.wrap("I am server!".getBytes()));
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client:

public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        SocketChannel client = SocketChannel.open();
        client.connect(new InetSocketAddress("localhost", 9999));
        client.configureBlocking(false);

        ByteBuffer buffer = ByteBuffer.allocate(50);
        while (true) {
            buffer.clear();
            int i = client.read(buffer);
            if (i > 0) {
                buffer.flip();
                System.out.println(new String(buffer.array(), 0, buffer.limit()));
            }

            client.write(ByteBuffer.wrap("I am a client!".getBytes()));
            Thread.sleep(500);
        }
    }
}

其他

运行在Linux kernel 2.6以后的OS中的Java应用,NIO的底层实现是根据OS提供的io多路复用接口epoll实现。

参考资料

原文地址:https://www.cnblogs.com/liushijie/p/5429046.html