NIO与Netty学习

NIO 与Netty学习

参考链接-B站-黑马课程

参考链接2-B站-黑马课程-Netty

Netty导学

  1. 互联网环境下,分布式系统大行其道,而分布式系统的根在于网络编程。而Netty是JAVA领域网络编程的王者。
  2. nio基础
  • non-blocking io 非阻塞io
  • 三大组件

1.1 核心一 Buffer(缓冲区)

  1. buffer则用来缓冲读写数据。
  2. 常见的buffer有
  • ByteBuffer(抽象类)
    • MappedByteBuffer
    • DirectByteBuffer
    • HeapByteBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloagBuffer
  • DoubleBuffer
  • CharBuffer

1.2 核心二 Channel(通道)

1. 基础概念

  1. Channel :是由java.nio.channel包定义的,表示IO源于目标打开的连接。Channel类似于传统的“流”,是读写数据的双向通道;只不过Channel本身不能直接访问数据,Channel只能与Buffer交互。尅从channel将数据读入buffer,也可以将buffer的数据写入channle。channel比stream更为底层
    在这里插入图片描述

  2. NIO的通道类似于流,但区别如下:

  • 通道可同时进行读写,而流只能读或者写;
  • 通道可实现异步读写数据
  • 通道可从缓冲读取数据,也可写数据到缓冲;
  1. BIO中的stream是单向的,如FileInputStream对象只能进行读取数据的操作,而NIO中的通道是双向的,可读也可写;
  2. 常用的Channel实现类
    • FileChannel:用于读取、写入、映射和操作文件。
    • DatagramChannel:通过UDP读写网络中的数据通道
    • SocketChannel: 通过TCP读写网络中的数据;
    • ServerSocketChannel可监听新进来的TCP连接,对每一个新进来的连接都会创建一个SocketChannel。

1.3 核心三 Selector

selector从字面意思不好立即,需要结合服务器的设计演化来理解它的用途

1.3.1 服务器设计的演化
  1. 多线程版设计
    在这里插入图片描述
    多线程版的缺点
  • 内存占用高
  • 线程上下文切换成本高
  • 只适合连接数少的场景
  1. 线程池版设计
    在这里插入图片描述
    线程池版缺点
  • 阻塞模式下, 线程仅能处理一个socket链接(处理socket1时,不能处理socket3)
  • 仅适合短连接场景
  1. selector版设计
    selector的作用就是配合一个线程来管理多个channel,获取这些channel上发生的事件,这些channel工作在非阻塞模式下,不会让线程吊死在一个channel上,适合连接数特别多,但流量低的场景(low traffic)。
    在这里插入图片描述
    调用selector的select()会阻直到channel发生了读写就绪事件,这些事件发生,select方法就会返回这些事件交给thread来处理。
1.3.2 Channel与Bytebuffer的基本使用
  1. 从channel读取数据,即向buffer写入数据。
  2. buffer切换读写模式
    • flIp
    • clear/compact();
  3. ByteBuffer的正确使用方式
    • 向buffer中写入数据,例如调用channel.read(buffer)
    • 调用flip()切换至读模式
    • 从buffer读取数据,例如调用buffer.get()
    • 调用clear()/compact()切换至写模式
    • 重复 1-4步骤
  4. ByteBuffer的内部结构
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
1.3.2 文件编程
  1. FileChannel只能工作在阻塞模式下。
  2. 获取
  3. 通过FileInputStream(只能读)、FileOutputStream(只能写)、RandomAccessFile(根据mode)获取channel;
  4. 强制写入
    OS出于性能考虑,会将数据缓存,不是立刻写入磁盘。可以调用force(true)方法将文件内容和元数据(文件的权限等信息)立刻写入磁盘。
  5. transferTo,底层会使用零拷贝,所以效率高。传入上限是最大只能为2G数据;
  6. Paths,Files,
    -Files. copy,move,delete,

2 网络编程与NIO

2.1 网络编程

2.1.1 非阻塞vs阻塞

1 阻塞

  • 在没有数据可读时,包括数据复制过程中,线程必须阻塞等待,不会占用CPU,但线程相当于闲置。
  • 32位JVM一个线程32k,64位JVM一个线程1024k,为了减少线程数,需要采用线程池技术
  • 但即便采用了线程池,如果有很多线程简历,但长时间inactive,会阻塞线程池中的所有线程 2 非2 非阻塞
  • 在某个channel没有可读事件时,线程不必阻塞,它可以去处理其他刻度时间的channel;
  • 数据复制过程中,线程实际还是阻塞的(AIO改进的地方)
  • 写数据是,线程只是等待数据写入channel即可,无需等待channel通过网络把数据发送出去
    3 多路复用
    线程必须配合selector才能完成对多个channel可读可写事件的监控,这称之为多路复用
  • 多路复用仅针对网络IO,普通文件IO没法多路复用
  • 如果不用selector的非阻塞模式,那么channel读取到的字节很多时候是0,而selector保证了有刻度事件才去读
  • channel输入的数据一旦准备好,会触发selector的可读事件
    4 阻塞
  • 默认情况下:ServerSocketChannel的accept方法和SocketChannel的read方法,都是阻塞的。阻塞是让出CPU,非阻塞是CPU空转,不会让出CPU。
  • 非阻塞模式,没有连接请求,没有读请求时候也在不断循环,这样是不合理的。CPU空转过高的使用方式也是不合理的。
2.1.1 selector编程
  1. channel注册到selector上;
1 外部调用
final SelectionKey selectionKey = ssc.register(selector, SelectionKey.OP_ACCEPT, null);

2 内部实际是, 即selector有register方法
  k = ((AbstractSelector)sel).register(this, ops, att);
  执行register时,内部创建 SelectionKeyImpl(channel, selector,attach);
  并将 SelectionKeyImpl对方存放到selector中的channelArray数组中
3 channel本身也维护了1个keys数组(类型:SelectionKey);
4.所以channel selector 是相互引用的

在这里插入图片描述
5. 事件的类型

3. SocketChannel

  1. ServerSocketChannel
    configureBlocking 可设置通道为非阻塞模式;
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(9999));
// 当设置为false时, 则影响到  SocketChannel accept = serverSocketChannel.accept();,即获取连接的方法不会阻塞了。若无真实连接进来则会返回null;
serverSocketChannel.configureBlocking(false);


// 若SocketChannel 设置为非阻塞,则read方法就是非阻塞的了
temp.configureBlocking(false);
ByteBuffer allocate = ByteBuffer.allocate(1024);
int len = temp.read(allocate);
// 在非阻塞模式下,若未读到数据则返回0

4. Selector

  1. 简单非阻塞模式的缺点
    • 没有连接请求时也一直在循环;
    • 没有读取请求时也一直在循环;
      上述两个情况都造成了系统CPU的浪费,CPU空转;
  2. 改进方式
    Selector:用于管理Channel,监测channel上是否有事件发生,连接事件、可读事件。无活可干时则阻塞等待;
  3. SelectionKey
    • 通过SekectionKey 在将来事件发生时,可以知道是什么事件,并且知道是哪个Channel发生的事件。
    • 事件类型:
      • accept (OP_ACCEPT = 1 << 4,16)
        ServerSocketChannel,会在有连接请求时触发
      • connect (8)
        是客户端,连接建立后触发。
      • read (1)
        表示有数据可读了
      • write (4)
        表示数据可以写了
  4. 事件使用
  • ServerSocketChannel 关注 连接事件;
  1. 事件发生后,要么处理要么cancel,不能置之不理
// 没有事件发生,则阻塞等待,只有当有事件发生时才继续执行
int select = selector.select();
// 有事件未处理时 则是不会阻塞的,
SelectionKey.cancel() 也可取消事件
 
只会向  selectedKey 集添加事件,不会从中删除
// 即发生事件时,要么处理,要么删除

// cancel 当客户端断开时,会触发read事件;所以要捕获异常并cancel该key; 将key及其对应的channel从selectors中真正删除。

  1. accept 在非阻塞模式且无连接进入的情况下回返回null;
    所以处理完一个key要将其删除;
  2. 处理客户端断开连接
  • 不管客户端是正常还是异常断开,在服务端都会收到一个读事件
  • 客户端正常断开,服务端收到的read结果为 -1;也要进行key.cancel()处理
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值