• [编织消息框架][网络IO模型]NIO(select and poll)


    上面测试论证系统内核在read data时会阻塞,如果我们在把第一个阶段解决掉那么性能就会提高

    NIO 编程
    JDK 1.4中的java.nio.*包中引入新的Java I/O库,其目的是提高速度。实际上,“旧”的I/O包已经使用NIO重新实现过,即使我们不显式的使用NIO编程,也能从中受益。速度的提高在文件I/O和网络I/O中都可能会发生,但本文只讨论后者。
    NIO 简介
    NIO我们一般认为是New I/O(也是官方的叫法),因为它是相对于老的I/O类库新增的(其实在JDK 1.4中就已经被引入了,但这个名词还会继续用很久,即使它们在现在看来已经是“旧”的了,所以也提示我们在命名时,需要好好考虑),做了很大的改变。但民间跟多人称之为Non-block I/O,即非阻塞I/O,因为这样叫,更能体现它的特点。而下文中的NIO,不是指整个新的I/O库,而是非阻塞I/O。
    NIO提供了与传统BIO模型中的Socket和ServerSocket相对应的SocketChannel和ServerSocketChannel两种不同的套接字通道实现。
    新增的着两种通道都支持阻塞和非阻塞两种模式。

    由于sun公司出技术要考虑兼容历史问题,所以新的NIO操作添加新的对象,其中比较重要的对象

    1.Channel 通道 

    2.Buffer 缓冲区

    3.Selector 多路复用器

    4.SelectionKey op key


    下面会先对基础知识进行介绍。

    1.通道 Channel
    我们对数据的读取和写入要通过Channel,它就像水管一样,是一个通道。通道不同于流的地方就是通道是双向的,可以用于读、写和同时读写操作。
    底层的操作系统的通道一般都是全双工的,所以全双工的Channel比流能更好的映射底层操作系统的API。而装载数据对象为Buffer
    Channel主要分两大类:
    SelectableChannel:用户网络读写
    FileChannel:用于文件操作

    2、缓冲区 Buffer
    Buffer是一个对象,包含一些要写入或者读出的数据。
    在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,也是写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
    缓冲区实际上是一个数组,并提供了对数据结构化访问以及维护读写位置等信息。
    具体的缓存区有这些:ByteBuffe、CharBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。他们实现了相同的接口:Buffer。

    我们只关心ByteBuffe即可


    3、多路复用器 Selector
    Selector是Java NIO 编程的基础。
    Selector提供选择已经就绪的任务的能力:Selector会不断轮询注册在其上的Channel,如果某个Channel上面发生读或者写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作。
    一个Selector可以同时轮询多个Channel,因为JDK使用了epoll()代替传统的select实现,所以没有最大连接句柄1024/2048的限制。所以,只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端。

    4、op key SelectionKey 

    SelectionKey 是socket操作集合,有OP_ACCEPT 接收新的socket连接,OP_CONNECT 客户端连接操作,OP_WRITE 数据写入系统操作,OP_READ 数据准备好

    要注意的是:由于SelectionKey 状态是叠加的,通过Selector定时轮询,会积累多个SelectionKey同多个op key,所以会返回 Set<SelectionKey> 集合,

    当操作完后要删除注册的SelectionKey或清掉状态,这点比较麻烦要开发者自行管理,不太人性

    而返回多个SelectionKey应用层不知道是那个socket来源,所以在OP_ACCEPT同OP_CONNECT 操作时就要调用 attach方法绑定标识,而里面用到黑科技 AtomicReferenceFieldUpdater 感兴趣读者可以看下源码

    小结:通过对象定义跟职责,我们大概组合下如果工作的

    1.能过Selector定时轮询,返回 Set<SelectionKey> 进行分发处理

    2.遍历Set<SelectionKey> 按不同 op key 切分不同handler 分而治之

    3.绑定socet标识,方便提取上下文

    4.处理完成后要向集合 移除 SelectionKey同清理状态

    5.读写数据 channel 通过Buffer处理

     nonblocking I/O 非阻塞模型:如前端比较熟悉的技术ajax轮询

     I/O multiplexing (select and poll) IO多路复用模型:select先阻塞,有活动套接字才返回。与blocking I/O相比,select会有两次系统调用,但是select能处理多个套接字。

    由于每个对象学习成本较大,加上需要相应的工作经验,估计要三四年网络开发编程经验,还有个比较恶心的地方jdk nio有BUG的,以后再介绍。

    了解这些技术起码知道有那些坑,实际使用时能避免出现,解决一个问题时要选择最优方案。

    选择netty框架是种不错的选择,毕竟不是每个人都有能力同充足时间开发的。

  • 相关阅读:
    bzoj3576 [Hnoi2014]江南乐
    codeforces 438D The Child and Sequence
    bzoj1926 [Sdoi2010]粟粟的书架
    bzoj1185 [HNOI2007]最小矩形覆盖
    bzoj1069 [SCOI2007]最大土地面积
    bzoj4569 [Scoi2016]萌萌哒
    西西爆难积分
    概率问题-距离的期望
    各类平均与数列极限
    三角恒等式
  • 原文地址:https://www.cnblogs.com/solq111/p/6734123.html
Copyright © 2020-2023  润新知