NIO

NIO

概述

  • BIO

    Blocking IO,阻塞型IO

  • NIO

    No Blocking IO,非阻塞型IO

  • 阻塞IO的弊端

    在等待的过程中,什么事也做不了

  • 非阻塞IO的好处

    不需要一直等待,当一切就绪了再去做

NIO与BIO的区别

  • 区别一

    BIO是阻塞的,NIO是非阻塞的

  • 区别二

    BIO是面向流的,NIO是面向缓冲区的

    BIO中数据传输是单向的,NIO中的缓冲区是双向的

NIO三大模块

  • 缓冲区

    用来存储数据

  • 通道

    用来建立连接和传输数据

  • 选择器

    监视通道状态

NIO创建缓冲区对象

  • 方法介绍

    方法名说明
    static ByteBuffer allocate(长度)创建byte类型的缓冲区
    static ByteBuffer wrap(byte[] array)创建一个有内容的byte类型缓冲区
  • 代码示例

    public class CreateByteBufferDemo1 {
        public static void main(String[] args) {
            //method1();
    
            //method2();
    
            ByteBuffer wrap = ByteBuffer.wrap("aaa".getBytes());
            for (int i = 0; i < 3; i++) {
                System.out.println(wrap.get());
            }
        }
    
        private static void method2() {
            byte [] bytes = {97,98,99};
            ByteBuffer byteBuffer2 = ByteBuffer.wrap(bytes);
            //缓冲区的长度3
            //缓冲区里面的内容就是字节数组的内容.
            for (int i = 0; i < 3; i++) {
                System.out.println(byteBuffer2.get());
            }
            System.out.println(byteBuffer2.get());
        }
    
        private static void method1() {
            ByteBuffer byteBuffer1 = ByteBuffer.allocate(5);
            //get
            for (int i = 0; i < 5; i++) {
                System.out.println(byteBuffer1.get());
            }
            System.out.println(byteBuffer1.get());
        }
    }
    

NIO缓冲区添加数据

  • 方法介绍

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mHfMcWts-1595219255060)(D:/杭州java/java_se/day14_网络编程01/笔记/img/10_NIO缓冲区添加数据.png)]

  • 代码示例

    public class ByteBufferDemo2 {
        public static void main(String[] args) {
    //        int position()		  当前要操作的索引
    //        int limit() 		  最多能操作到哪个索引
    //        int capacity()		  缓冲区的总长度
            ByteBuffer byteBuffer = ByteBuffer.allocate(10);
            System.out.println(byteBuffer.position());//0
            System.out.println(byteBuffer.limit());//10
            System.out.println(byteBuffer.capacity());//10
    
    //        put(byte b)		  一次添加一个字节
    //        byteBuffer.put((byte) 97);
    //        System.out.println(byteBuffer.position());
    //        System.out.println(byteBuffer.limit());
    //        System.out.println(byteBuffer.capacity());
    
    //        put(byte[] src)		 一次添加一个字节数组
    //        byteBuffer.put("aaa".getBytes());
    //        System.out.println(byteBuffer.position());//3
    //        System.out.println(byteBuffer.limit());//10
    //        System.out.println(byteBuffer.capacity());//10
    
    //        position(int newPosition) 修改position
    //        byteBuffer.position(1);
    
    //        limit(int newLimit)	  修改limit
    //        byteBuffer.limit(5);
    //        System.out.println(byteBuffer.position());
    //        System.out.println(byteBuffer.limit());
    //        System.out.println(byteBuffer.capacity());
    
    //        int remaining()		  还有多少能操作
    //        boolean hasRemaining()	  是否还有能操作的
    
            byteBuffer.put("0123456789".getBytes());
            System.out.println(byteBuffer.remaining());
            System.out.println(byteBuffer.hasRemaining());
        }
    }
    

NIO缓冲区获取数据

  • 方法介绍

    方法名介绍
    flip()切换读写模式(写à读)
    get()读一个字节
    get(byte[] dst)读多个字节
    get(int index)读指定索引的字节
    rewind()将position设置为0,可以重复读
    clear()数据读写完毕(读->写)
    array()将缓冲区转换成字节数组返回
public class ByteBufferDemo3 {
    public static void main(String[] args) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        byteBuffer.put("abc".getBytes());

//        flip()  切换读写模式(写读)
        byteBuffer.flip();
//        get()   读一个字节
//        while(byteBuffer.limit() != byteBuffer.position()){
//            System.out.println((char) byteBuffer.get());
//        }

        for (int i = 0; i < byteBuffer.limit(); i++) {
            System.out.println((char) byteBuffer.get());
        }

//        get(byte[] dst) 读多个字节
//        byte [] bytes = new byte[byteBuffer.limit()];
//        byteBuffer.get(bytes);
//        System.out.println(new String(bytes));

//        get(int index)  读指定索引的字节
//        System.out.println((char) byteBuffer.get(0));

//        rewind()    将position设置为0,可以重复读
//        byteBuffer.rewind();
//        for (int i = 0; i < byteBuffer.limit(); i++) {
//            System.out.println((char) byteBuffer.get());
//        }

//        clear()     数据读写完毕(读->写)
        byteBuffer.clear();
        byteBuffer.put("qqq".getBytes());
//        array()     将缓冲区转换成字节数组返回

        byte[] bytes = byteBuffer.array();
        System.out.println(new String(bytes));
    }
}

小结

  1. 需求:我要把数据写到缓冲区中。

    数据是从外面进入到缓冲区的,所以缓冲区在做读数据的操作。

  2. 需求:我要把数据从缓冲区中读出来。

    数据是从缓冲区里面到外面的。所以缓冲区在做写数据的操作。

  3. capacity:容量(长度)
    limit: 界限(最多能读/写到哪里)
    posotion:位置(读/写哪个索引)

  4. 获取缓冲区里面数据之前,需要调用flip方法

  5. 再次写数据之前,需要调用clear方法,

    但是数据还未消失,等再次写入数据,被覆盖了才会消失。

NIO通道客户端

  • 客户端实现步骤

    1. 打开通道
    2. 指定IP和端口号
    3. 写出数据
    4. 释放资源
  • 示例代码

    public class NIOClient {
        public static void main(String[] args) throws IOException {
            //1.打开通道
            SocketChannel socketChannel = SocketChannel.open();
    
            //2.指定IP和端口号
            socketChannel.connect(new InetSocketAddress("127.0.0.1",10000));
    
            //3.写出数据
            ByteBuffer byteBuffer = ByteBuffer.wrap("一点寒毛先制".getBytes());
            socketChannel.write(byteBuffer);
    
            //4.释放资源
            socketChannel.close();
        }
    }
    

NIO通道服务端

  • NIO通道

    • 服务端通道

      只负责建立建立,不负责传递数据

    • 客户端通道

      建立建立并将数据传递给服务端

    • 缓冲区

      客户端发送的数据都在缓冲区中

    • 服务端通道内部创建出来的客户端通道

      相当于客户端通道的延伸用来传递数据

NIO选择器

  • 概述

    选择器可以监视通道的状态,多路复用

选择器对象

  • Selector

    选择器对象

  • SelectionKey

    绑定的key

  • SelectableChannel

    能使用选择器的通道

    • SocketChannel
    • ServerSocketChannel

NIO选择器改写服务端

  • 实现步骤

    1. 打开一个服务端通道(open)

    2. 绑定对应的端口号

    3. 通道默认是阻塞的,需要设置为非阻塞

    4. 打开一个选择器(门卫大爷)

    5. 将选择器绑定服务端通道,并监视服务端是否准备好

    6. 如果有客户端来连接了,大爷会遍历所有的服务端通道,谁准备好了,就让谁来连接
      连接后,在服务端通道内部,再创建一个客户端延伸通道

    7. 如果客户端把数据传递过来了,大爷会遍历所有的延伸通道,谁准备好了,谁去接收数据

hannel

  • ServerSocketChannel

NIO选择器改写服务端

  • 实现步骤

    1. 打开一个服务端通道(open)

    2. 绑定对应的端口号

    3. 通道默认是阻塞的,需要设置为非阻塞

    4. 打开一个选择器(门卫大爷)

    5. 将选择器绑定服务端通道,并监视服务端是否准备好

    6. 如果有客户端来连接了,大爷会遍历所有的服务端通道,谁准备好了,就让谁来连接
      连接后,在服务端通道内部,再创建一个客户端延伸通道

    7. 如果客户端把数据传递过来了,大爷会遍历所有的延伸通道,谁准备好了,谁去接收数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值