第一课 NIO

来源:互联网 发布:幼儿园网络信息 编辑:程序博客网 时间:2024/06/18 00:18

传统IO的特点

  • 阻塞点 server.accept(); inputStream.read(bytes);
  • 单线程情况下只能有一个客户端
  • 用线程池可以有多个客户端连接,但是非常消耗性能
  • 无法作为长连接服务器可以做短连接(旧版本Tomcat)

这里写图片描述

NIO的关键词

ServerSocketChannel ServerSocketSocketChannel       SocketSelectorSelectionKey

这里写图片描述

NIO的一些问题

1、客户端关闭的时候会抛出异常,死循环解决方案        int read = channel.read(buffer);        if(read > 0){            byte[] data = buffer.array();            String msg = new String(data).trim();            System.out.println("服务端收到信息:" + msg);            //回写数据            ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());            channel.write(outBuffer);// 将消息回送给客户端        }else{            System.out.println("客户端关闭");            key.cancel();        }2、selector.select();阻塞,那为什么说nio是非阻塞的IO?    selector.select()    selector.select(1000);不阻塞    selector.wakeup();也可以唤醒selector    selector.selectNow();也可以立马返还,视频里忘了讲了,哈,这里补上3、SelectionKey.OP_WRITE是代表什么意思OP_WRITE表示底层缓冲区是否有空间,是则响应返还true

NIOServer示例

/** * NIO服务端 *  */public class NIOServer {    // 通道管理器    private Selector selector;    /**     * 获得一个ServerSocket通道,并对该通道做一些初始化的工作     *      * @param port     *            绑定的端口号     * @throws IOException     */    public void initServer(int port) throws IOException {        // 获得一个ServerSocket通道        ServerSocketChannel serverChannel = ServerSocketChannel.open();        // 设置通道为非阻塞        serverChannel.configureBlocking(false);        // 将该通道对应的ServerSocket绑定到port端口        serverChannel.socket().bind(new InetSocketAddress(port));        // 获得一个通道管理器        this.selector = Selector.open();        // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,        // 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。        serverChannel.register(selector, SelectionKey.OP_ACCEPT);    }    /**     * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理     *      * @throws IOException     */    public void listen() throws IOException {        System.out.println("服务端启动成功!");        // 轮询访问selector        while (true) {            // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞            selector.select();            // 获得selector中选中的项的迭代器,选中的项为注册的事件            Iterator<?> ite = this.selector.selectedKeys().iterator();            while (ite.hasNext()) {                SelectionKey key = (SelectionKey) ite.next();                // 删除已选的key,以防重复处理                ite.remove();                handler(key);            }        }    }    /**     * 处理请求     *      * @param key     * @throws IOException     */    public void handler(SelectionKey key) throws IOException {        // 客户端请求连接事件        if (key.isAcceptable()) {            handlerAccept(key);            // 获得了可读的事件        } else if (key.isReadable()) {            handelerRead(key);        }    }    /**     * 处理连接请求     *      * @param key     * @throws IOException     */    public void handlerAccept(SelectionKey key) throws IOException {        ServerSocketChannel server = (ServerSocketChannel) key.channel();        // 获得和客户端连接的通道        SocketChannel channel = server.accept();        // 设置成非阻塞        channel.configureBlocking(false);        // 在这里可以给客户端发送信息哦        System.out.println("新的客户端连接");        // 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。        channel.register(this.selector, SelectionKey.OP_READ);    }    /**     * 处理读的事件     *      * @param key     * @throws IOException     */    public void handelerRead(SelectionKey key) throws IOException {        // 服务器可读取消息:得到事件发生的Socket通道        SocketChannel channel = (SocketChannel) key.channel();        // 创建读取的缓冲区        ByteBuffer buffer = ByteBuffer.allocate(1024);        int read = channel.read(buffer);        if(read > 0){            byte[] data = buffer.array();            String msg = new String(data).trim();            System.out.println("服务端收到信息:" + msg);            //回写数据            ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());            channel.write(outBuffer);// 将消息回送给客户端        }else{            System.out.println("客户端关闭");            key.cancel();        }    }    /**     * 启动服务端测试     *      * @throws IOException     */    public static void main(String[] args) throws IOException {        NIOServer server = new NIOServer();        server.initServer(8000);        server.listen();    }}