java NIO

377 查看

NIO是什么就不在此文展开,这篇主要来介绍下我们要怎样通过java NIO来构建一个服务客户端程序的。

0x01 涉及知识点

NIO建立一个服务端和客户端程序主要涉及的知识点有:

  1. channel

  2. selector

  3. buffer

如果通过C/C++写过通信程序的应该知道都是通过linux提供的系统调用来完成,java NIO的实现思想上没有什么变化只是在实现方式上换了一种新的概念,并提供了更友好的开发模式供开发人员更加简便快捷的来实现自己想要的功能。

  • channel:NIO的通信完全依赖与channel,数据的写入和读取都是通过channel从buffer中写入/读取。

  • selector:和linux上的select调用一样的功能,监听已经注册在上面的socket文件描述符,java NIO监听channel上的事件。主要有:OP_CONNECT()、OP_ACCEPT、OP_READ、OP_WRITE。

  • buffer主要是从channel中读出数据或者写入数据到channel。

0x02 server

public class NioServer {

    public static void main(String[] args) {
        try {
            // 建立一个serversocketchannel,用于监听是否有连接到来
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 设置为非阻塞模式
            serverSocketChannel.configureBlocking(false);
            // 绑定监听的地址
            serverSocketChannel.bind(new InetSocketAddress(8080));
            // 获取一个selector
            Selector selector = Selector.open();
            // 将channel注册到selector中,并且这个channel关心的是accept事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            while(true) {
                int readySize = selector.select();
                if(readySize == 0) {
                    continue;
                }
                // 获取有事件到来的selectKeys
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                // 处理到来的事件
                for(Iterator<SelectionKey> iter = selectionKeys.iterator(); iter.hasNext(); ) {
                    SelectionKey selectionKey = iter.next();
                    // 要将已经被处理的selectionKey删除掉
                    iter.remove();
                    if(selectionKey.isAcceptable()) {
                        System.out.println("acceptable");
                        ServerSocketChannel listenChannel = (ServerSocketChannel) selectionKey.channel();
                        /* 获取连接进来的channel */
                        SocketChannel socketChannel = listenChannel.accept();
                        socketChannel.configureBlocking(false);
                        socketChannel.write(ByteBuffer.wrap(new String("java NIO").getBytes()));
                        socketChannel.register(selector, SelectionKey.OP_READ);
                    } else if(selectionKey.isReadable()) {
                        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                        ByteBuffer byteBuffer = ByteBuffer.allocate(100);
                        int readSize = socketChannel.read(byteBuffer);
                        /* 相应的channel连接断开了将其关闭掉 */
                        if(readSize == -1) {
                            socketChannel.close();
                            selectionKey.cancel();
                            continue;
                        }
                        /* 将客户端写入的数据显示出来 */
                        byte[] bytes = byteBuffer.array();
                        String message = new String(bytes).trim();
                        System.out.println(message);
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }
}

0x03 client

public class NioClient {

    public static void main(String[] args) {
        SocketChannel socketChannel = null;
        try {
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            // 发起连接请求
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
            Selector selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            while (true) {
                int readySize = selector.select();
                if(readySize == 0) {
                    continue;
                }
                Set<SelectionKey> selectionKeys =  selector.selectedKeys();
                for(SelectionKey selectionKey : selectionKeys) {
                    SocketChannel clientChannel = (SocketChannel)selectionKey.channel();
                    if(selectionKey.isConnectable()) {
                        /* 连接还没建立完全,等待连接建立完成 */
                        if(clientChannel.isConnectionPending()) {
                            clientChannel.finishConnect();
                        }
                        clientChannel.register(selector, SelectionKey.OP_READ);
                    } else if (selectionKey.isReadable()) {
                        System.out.println("readable");
                        ByteBuffer byteBuffer = ByteBuffer.allocate(100);
                        System.out.println(clientChannel.read(byteBuffer));
                        byte[] bytes = byteBuffer.array();
                        String message = new String(bytes).trim();
                        System.out.println(message);
                    }
                    selectionKeys.remove(selectionKey);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }
}

0x04 参考

NIO相关的概念可以点这里