zoukankan      html  css  js  c++  java
  • 解锁网络编程之NIO的前世今生

    个人博客网:https://wushaopei.github.io/    (你想要这里多有)

    NIO 内容概览:

    •     NIO 网络编程模型
    •     NIO 网络编程详解
    •     NIO 网络编程实战
    •     NIO 网络编程缺陷

    一、NIO网络编程模型

    1、编程模型定义

    NIO :  又叫Non-blocking I/O或New I/O;全新的输入输出标准库;

              做为原始I/O的补充,为了高性能和高并发的场景使用。

    模型:对事物共性的抽象;

    编程模型:对编程共性的抽象;

    2、BIO网络模型

           

    •  服务端启动,开始建立监听客户端的连接请求;
    • 客户端启动,向服务器端发起建立连接请求;
    • 服务器在收到客户端的请求后,将会创建一个新的线程;
    • 服务端新创建的线程会与客户端建立socket连接,用于响应客户端的请求,通知客户端连接建立成功,你随时可以给我发送数据。
    • 服务器端处理完客户端的请求之后,就会处于等待状态,等待客户端再次发起请求

           

    服务端为每一个客户端建一个线程,一旦客户端请求过多,服务端线程数量也会增多,服务端压力增大。

    3、BIO网络模型缺点

    • 阻塞式I/O模型,会导致服务器端的业务线程会因阻塞IO的问题一直阻塞等待客户端发起请求,如果客户端不发起请求,服务端的业务线程会一直存在,就会耗费大量系统资源

    • 弹性伸缩能力差:服务器端的线程数与客户端的个数呈1比1的关系

    • 多线程耗资源 : 每一个线程都会对CPU的调度资源进行占用,一旦占用而不释放,则会导致资源的紧缺、甚至系统服务的异常宕机

    4、NIO网络模型猜想

    基于非阻塞 I/O , 设计应对高并发场景编程模型

    图解分析:NIO架构中,客户端的个数与服务器端的线程数呈M:1的关系

    5、NIO 网络模型

    第一步:注册连接并提供服务:Selector 中初始化注册并建立连接事件,提供给Client建立连接的服务;client通过Selector连接与AcceptorHandler 发送创建客户端的连接,并又AcceptorHandler方法返回响应结果;同时该AcceptorHandler方法向Selector中注册可读事件(Client连接客户端成功后)

    第二步:提供服务:client 发送请求,Selector中对注册状态及客户端可读性验证,正常情况下,已通过第一步,所以直接连接到处理器进行读写操作,根据需求执行业务逻辑,并响应给客户;

    第三步:客户端连接可读,在向client响应客户端请求后,注册连接可读事件到Selector 中,所注册的是具体执行业务的Handler

    6、NIO网络模型优化

    1. 非阻塞IO模型,服务器端提供一个单线程的selector来统一管理所有客户端接入的连接,并负责监听每个连接所关心的事件

    2. 弹性伸缩能力加强,服务器端一个线程处理所有客户端的连接请求,客户端的个数与服务器端的线程数呈M比1的关系

    3. 单线程节省资源,避免了线程的频繁创建和销毁,同时也避免了多个线程之间上下文的切换,提高了执行效率

    二、NIO网络编程详解

    NIO核心

    • Channel:通道
    • Buffer : 缓冲区
    • Selector : 选择器 或 多路复用器

    1、NIO核心类之Channel

    Channel 具有双向性、非阻塞性、操作唯一性。

    channel是信息传输的通道,是jdk NIO中对输入输出方法的另一种抽象,类比IO中的流,与流不同之处在于,channel具有双向性,而流是单向传输的,一个流必须是InputStream或OutputStream的子类,而通道可以用于读写或二者同时进行。channel可以工作在非阻塞模式下,构成NIO的基础。在NIO中,操作channel的唯一方式是使用buffer,通过buffer操作channel,实现数据块的传输。

    channel的实现:

    1. 文件类:FileChannel,用于对文件的读写
    2. UDP类:DatagramChannel, 用于UDP的数据读写
    3. TCP类:ServerSocketChannel/SocketChannel,用于TCP的数据读写

    Socket的使用:

    Channel的使用:

    2、NIO核心类之Buffer

    Buffer:缓冲区,它提供唯一与channel进行交互的方式,作用是读写channel中的数据。Buffer从本质上说是一块内存区域,它是一块可以写入数据,读取数据的内存。

    Buffer的属性

    Capacity:分配的buffer容量,一旦写入的最大字节数超过这个容量,需要将其清空之后,才能继续往里面写数据

    Position:当前操作的位置,初始值为0,最大值:容量值-1

    Limit:上限,写模式下等于Capacity,读模式下等于最多能读取的数据

    Mark:标记,记录mark的位置,调用reset方法时position会回到mark的位置

    Buffer的使用:

      /*
       * 初始化长度为10的byte类型 buffer
       */
      ByteBuffer.allocate(10);

      /*
       * 向byteBuffer中写入三个字节
       */
      byteBuffer.put("abc".getBytes(Charset.forName("UTF-8")));

      /*
       * 将byteBuffer从写模式切换成读模式
       */
      byteBuffer.flip():

      /*
       * 将b先调用get方法读取下一个字节
       * 再调用reset方法将position重置到mark位置
       */
      byteBuffer.get():
      byteBuffer.reset();

      /*
       * 调用clear方法,将所有属性重置
       */
      byteBuffer.clear();

    3、NIO核心类之Selector

    Selector 选择器/多路复用器

    作用:I/O就绪选择

    地位:NIO网络编程的基础

    SelectionKey 选择键

    四种就绪状态常量:连接就绪、接受就绪、读就绪、写就绪

    Selector的使用:

    最重要的应该就是代码片段3: 在这一步对就绪事件进行监听,如果一直不通过,就一直阻塞等待,直到有就绪事件发生,并注册通过检测有效,方才放行

    4、NIO编程实现步骤

    第一步:创建Selector

    第二步:创建ServerSocketChannel,并绑定监听端口

    第三步:将Channel设置为非阻塞模式

    第四步:将Channel注册到Selector上,监听连接事件

    第五步:循环调用Selector的select方法,检测就绪情况

    第六步:调用selectedKeys方法获取就绪channel集合

    第七步:判断就绪事件种类,调用业务处理方法

    第八步:根据业务需要决定是否再次注册监听事件,重复执行第三步操作

    码云:https://gitee.com/wushaopei/IO/tree/master/nio-chai-room

  • 相关阅读:
    单例模式创建
    盛最多水的容器
    魔术索引
    钢条切割
    比较版本号
    矩阵中的路径
    机器人的运动范围
    计网基础问题
    Linux 下android环境的配置
    Fedora15下安装Android开发环境
  • 原文地址:https://www.cnblogs.com/wushaopei/p/11979138.html
Copyright © 2011-2022 走看看