美文网首页
Netty网络编程之NIO概览与简单应用

Netty网络编程之NIO概览与简单应用

作者: 社会我大爷 | 来源:发表于2017-07-28 22:43 被阅读51次

    1.关于NIO

    Java NIO即Java Non-blocking IO(Java非阻塞I/O),是Jdk1.4之后增加的一套操作I/O工具包,又被叫做Java New IO。

    (1)Reactor模式
    Reactor即反应器,就是我们将事件注册到Reactor中,当有相应的事件发生时,Reactor便会告知我们有哪些事件发生了,我们再根据具体的事件去做相应的处理。在NIO里主要是Selector多路复用模型。

    (2)BIO(同步阻塞IO)和NIO的区别

    BIO在调用read/write的时候会阻塞线程,也就是就算某个时刻你的socket并没有数据需要传输,
    但是你的socket线程却仍然会被阻塞在read/write方法上,所以BIO是一个socket连接一个线程。
    NIO与BIO不同,它主要依靠事件监听反应器进行工作,一个监听器可以监听好几个socket连接,只有在socket有事件发生(如读写数据,连接到达等)的时候才进行事件分发,
    开启线程去处理事件(一个请求一个线程),所以在高并发的时候NIO是优于BIO的。
    并且NIO有了缓冲区的概念,不管是File IO还是Socket IO都是在和Buffer相互读取,
    NIO可以先将通道数据读到缓冲区中再进行操作,避免了逐字节或逐行读取的性能开销。

    NIO主要可以分为四个模块,分别是Buffer(数据缓冲区),Channel(数据通道),Selector(监听器),Charset(字符集)。

    2.Buffer(数据缓冲区)

    缓冲区(Buffer)就是在内存中预留指定字节数的存储空间用来对输入/输出(I/O)的数据作临时存储,这部分预留的内存空间就叫做缓冲区;

    在Java NIO中,缓冲区的作用也是用来临时存储数据,可以理解为是I/O操作中数据的中转站。
    缓冲区直接为通道(Channel)服务,写入数据到通道或从通道读取数据。

    java.nio.Buffer是一个抽象类,直接继承Buffer的缓冲区类有七种:
    ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffer。
    其中MappedByteBuffer继承ByteBuffer,专门用于内存映射,可以处理大文件读写等。

    Buffer有四个属性,

    private int mark = -1;
    private int position = 0;
    private int limit;
    private int capacity; 
    Capacity 容量,即可以容纳的最大数据量;在缓冲区创建时被设定并且不能改变
    Limit 上界,缓冲区中当前数据量
    Position 位置,下一个要被读或写的元素的索引
    Mark 标记,调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置即position=mark

    具体的操作方法主要有clear(清空缓冲区),flip(把缓冲区状态改为写状态),put(向缓冲区写入数据),get(从缓冲区读取数据)。

    3.Channel(数据通道)

    Channel相当于BIO里面的Stream(数据流),但Channel与Stream不同,Channel是双向的,
    可以向通道两边传输数据,而不用像BIO那样要专门建立一个输入流和一个输出流。
    I/O可以分为文件IO和流IO,那么Channel对应的就可以分为文件通道(FileChannel)和流通道(流通道就是套接字通道,SocketChannel),NIO中Channel接口主要的通道实现类有以下几种:

    FileChannel 文件通道,用于操作文件I/O
    SocketChannel 套接字通道,用于TCP协议,客户端连接服务器后,
    服务器和客户端都会有一个SocketChannel,就可以互相发送数据了
    ServerSocketChannel 服务器套接字通道,用于TCP连接响应客户端连接

    通道可以以阻塞(blocking)或非阻塞(non-blocking)模式运行,阻塞模式会一直等待某个操作直到返回结果;非阻塞不会一直等待,要么返回null,要么返回执行完的结果。

    4.Selector(监听器)

    Selector是NIO的核心,

    (1)选择器的创建
    java.nio.channels.Selector提供了一系列的静态方法,可以直接调用,

    //创建选择器
    Selector sle =Selector.open();
    Selector(选择器)提供了下面方法:

    open():打开一个选择器
    isOpen():检查一个选择器实例是否打开
    provider():返回一个SelectorProvider
    keys():返回注册键集合
    selectedKeys():返回已选择键集合
    selectNow():立刻执行选择,非阻塞,若没有已准备好的通道则立即返回0
    select(long timeout):执行选择,超过指定毫秒数则返回
    select():执行选择,会一直阻塞直到有准备就绪的通道
    wakeup():停止选择
    close():关闭选择器

    (2)轮询获取注册到选择器中通道感兴趣的操作

    //创建选择器
    Selector sle =Selector.open();
    //创建socket服务器通道
    ServerSocketChannel socketChn=ServerSocketChannel.open();
    /**
    * 绑定端口
    * InetSocketAddress是SocketAddress的子类
    /
    socketChn.socket().bind(new InetSocketAddress(65535));
    //设置是否非阻塞
    socketChn.configureBlocking(false);
    /
    *
    * 将通道注册到选择器,指定通道兴趣是等待接收连接
    * NIO中定义了4中可选择操作:OP_READ(读)、OP_WRITE(写)、OP_CONNECT(连接)、OP_ACCEPT(接受),
    * 这些常量在SelectionKey中定义
    */
    SelectionKey key = socketChn.register(sle, SelectionKey.OP_ACCEPT);
    //使用while循环轮询获取注册到选择器中通道感兴趣的操作
    while(true){
    //选择注册到选择器中通道感兴趣的键,此方法是阻塞的,直到有感兴趣的事件发生
    // int n=sle.select();
    //立即查询,非阻塞
    int n=sle.selectNow();
    Iterator<SelectionKey> iter = sle.selectedKeys().iterator();
    while (iter.hasNext()) {
    SelectionKey keyy = iter.next();
    iter.remove();
    // ......
    }
    //close()方法可以关闭选择器
    sle.close();
    }

    (3)poll和epoll 选择器的内部实现

    选择器为通道服务,通道事先告诉选择器:“我对某些事件感兴趣,如可读、可写等“,

    选择器在接受了一个或多个通道的委托后,开始选择工作,它的选择工作就完全交给操作系统,linux下即为poll或epoll。

    5.Charset(字符集)

    主要是指java.nio.charset包下的一系列工具类,

    NIO提供了CharsetDecoder和CharsetEncoder进行字符集的编码和解码。

    相关文章

      网友评论

          本文标题:Netty网络编程之NIO概览与简单应用

          本文链接:https://www.haomeiwen.com/subject/pxxqlxtx.html