zoukankan      html  css  js  c++  java
  • 2018/1/19 Netty学习笔记(一)

    这段时间学了好多好多东西,不过更多是细节和思想上的,比如分布式事物,二次提交,改善代码质量,还有一些看了一些源码什么的;

    记录一下真正的技术学习,关于Netty的学习过程;

    首先说Netty之前先说一下BIO,NIO和AIO的区别吧,我这里对于AIO只说个大概,下午或者晚上有时间会写个具体的,其实本来想说说websocket的不过太基础了,各位百度下就行;

    BIO,NIO和AIO的区别
    BIO也就是同步阻塞的I/O,由JAVA程序自己处理I/O流操作;一个线程启用I/O请求后,必须等I/O处理完毕才能进行下一步;
    NIO是同步非阻塞的I/O,还是由JAVA处理应用操作,不过单独开启一个线程去做I/O处理,而且会将数据读写到一个Buffer缓冲区中,之后交由OS去进行处理,缺点是需要多路复用器不断去轮询,在触发I/O操作后,用户线程也会需要时不时的去访问查看是否已经完成(jdk7后已经使用了epoll进行了改善)
    AIO也就是NIO2.0,只需要发起一个I/O请求,之后具体的I/O操作都交由系统完成,系统在完成后会自行通知程序;

    不管是NIO还是AIO都是避免了传统BIO使用TCP连接创建输出和输入流通道进行通信的弊端,它们使用的是http长连接建立了一个可读写的通道(channel);

    Channel 管道(这里只说网络读写的Channel (SelecttableChannel 它有两个子类SocketChannel和ServerSockerChannel)避免了传统BIO的三次握手模型建立的OutputStream,InputStream连接通道),既可以读也可以写,也可以读写同时进行,并且channel上有四种状态位,分别是(Connect 连接状态,Accept 阻塞状态,Read 可读状态,Write 可写状态)不管是读写数据都是要先进入一个Buffer中,
    而Buffer其实也是一个对象,有对应JAVA八种基本数据类型的八种缓存区,但我们一般使用ByteBuffer对象进行读写的存储就够了;


    Selector 多路复用器,管理着一个注册的通道集合的信息和它们的就绪状态(使用轮询),如果某个通道发生了读写操作,会被它轮询出来,并通过SelectionKey可以取得就绪的Channel集合,从而进行后续的I/O操作;
    一个Selector可以管理成千上万个Channel通道,如果使用传统的轮询机制就会使得性能很底下,所以JDK使用了epoll(内部对于通道的节点位置使用红黑树存储,对于每个通道都添加了一个事件,只有当进程调用了一定的方法后,扫描才会被触发,而且可以并利用红黑树快速找到通道的节点位置)
    Selector模式: 当管道注册到选择器以后,selector会分配给每个管道一个key值,相当于标签.selector选择器是以轮询的方式方式进行查找注册的所有IO事件(管道),当我们的IO事件(管道准备就绪后),selector会识别,并通过对应的key值找到对应的管道,进行相关的数据处理操作(从管道中读获写数据,读的话就是写到我们的数据缓冲区中).

    每个管道都有不同的事件状态,以便选择器查找;
    SelectionKey.OP_CONNECT
    SelectionKey.OP_ACCEPT
    SelectionKey.OP_READ
    SelectionKey.OP_WRITE


    //Buffer api
    public void test() {
    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
    byteBuffer.put((byte) 1);
    byteBuffer.put((byte) 2);
    System.out.println(byteBuffer);
    // 打印此缓冲区,注意看它的结构 java.nio.HeapByteBuffer[pos=2 lim=10 cap=10]
    // pos:相当于一个游标,lim是具体长度,cap是容量上限,可以看到现在lim长度不对
    // 复位
    byteBuffer.flip();
    System.out.println(byteBuffer);
    // 此时再打印 java.nio.HeapByteBuffer[pos=0 lim=2 cap=10]可以看到游标变成了0,lim也正常了;
    //为什么会这样?
    /* public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
    }*/
    //看源码就知道了,那么如果不复位会发生什么呢?当你想取得数据的时候会发现会把后面没有数据的部分也打印出来
    //我们在复位的情况下打印下试试
    for (int i = 0; i < byteBuffer.limit(); i++) {
    byte b = byteBuffer.get(i);
    System.out.print(b+" ");
    }
    //结果为1 2
    //再看看不复位的情况下是什么 1 2 0 0 0 0 0 0 0 0 ,也就是说我们要保证limit,也就是实际长度的准备性

    //事实上,如果我们使用调用get()方法,也就是不通过索引查找数据,并且在没有复位的情况下,会连1 2都显示不出来,而是直接显示后面的默认值数据,因为get方法是以pos游标当前处往后推,并且还会导致溢出异常,因为不复位的情况下,limit是最大容量,也就是10;就算是默认值数据,也是以下标为准的,也就是10个数据,最大下标就是9,而get()会一直到10;

    }

  • 相关阅读:
    第9章 垄断市场中的企业决策
    第8章 完全竞争市场中的企业决策
    第7章 生产产出的决策分析
    第6章 成本分析
    第5章 生产要素投入的决策分析
    C++_函数指针的内容和应用
    大数据的框架-流程梳理
    数字图像处理_基本概念
    C++_项目开发与Cmake构建工具
    终端--通信和传输协议
  • 原文地址:https://www.cnblogs.com/yangfeiORfeiyang/p/8316418.html
Copyright © 2011-2022 走看看