深入解析NIO编程

3.NIO编程(重点)

与Socket类和ServerSocket类相对应,NIO也提供了SocketChannel和ServerSocketChannel2种不同的套接字通道实现。这2种新增的通道都支持阻塞和非阻塞2种模式。
  1. NIO类库简介
    1、缓冲区Buffer:
    (1)Buffer是一个对象,它包含一些要写入或者要读出的数据。而在面向流的IO中,可以将数据直接写入或读到Stream流对象中。在NIO库中,所有数据都是用缓冲区处理的。
    (2)缓冲区实质上是一个数组,通常是一个字节数组。还提供了对数据的结构化访问以及维护读写位置等信息。
    (3)最常用的缓存区是ByteBuffer。每一种Java基本类型(除了Boolean类型)都对应有一种缓冲区。
    (4)每一个Buffer类都是Buffer接口的一个子实例。除了ByteBuffer提供了一些特有的操作方便网络读写外,每一个Buffer类都有完全一样的操作,只是处理的数据类型不一样。
    2、通道Channel:
    (1)Channel是一个通道,网络数据通过Channel读取和写入。通道与流的不同之处在于通道是双向的,而流只是在一个方向上移动。通道可以用于读写同时进行。
    (2)因为Channel是全双工的,所以它可以比流更好地映射底层操作系统的API。因为特别是在UNIX网络编程模型中,底层操作系统的通道都是全双工的,同时支持读写操作。
    3、多路复用器Selector:
    (1)Selector会不断轮询注册在其上的Channel,如果某个Channel上面发生读或写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的IO操作。
    (2)一个多路复用器Selector可以同时轮询多个Channel,由于JDK使用了epoll代替传统的select实现,所以它并没有最大连接句柄的限制。

  2. NIO服务端序列图
    在这里插入图片描述

    1.打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端连接的父管道
    2.绑定监听接口,设置连接为非阻塞模式。
    3.创建Reactor线程,创建多路复用器并启动线程。
    4.将ServerSocketChannel注册到Reactor线程的多路复用器Selector上,监听ACCEPT事件。
    5.多路复用器在线程run方法的无限循环体内轮询准备就绪的Key。
    6.Selector监听到有新的客户端接入,处理新的接入请求,完成TCP三次握手,建立物理链路。
    7.设置客户端链路为非阻塞模式。
    8.将新接入的客户端连接注册到Reactor线程的多路复用器上,监听读操作,读取客户端发送的消息
    9.异步读取客户端请求消息到缓冲区
    10.对ByteBuffer进行编解码,如果有半包消息指针reset,继续读取后续的报文,将解码成功的消息封装成Task,投递到业务线程池中。
    11.将POJO对象encode成ByteBuffer,调用SocketChannel的异步write接口,将消息异步发送给客户端。
    PS:如果发送区TCP缓冲区满,会导致写半包。此时,需要注册监听写操作位,循环写,直到整包消息写入TCP缓存区。

  3. NIO客户端序列图
    在这里插入图片描述
    1.打开SocketChannel,绑定客户端本地地址(可选,默认会随机分配一个可用的本地地址)。
    2.设置SocketChannel为非阻塞模式,同时设置客户端连接的TCP参数。
    3.异步连接服务端。
    4.判断是否连接成功,如果成功,则直接注册读状态位到Selector中;如果当前没有连接成功(异步连接,返回false,说明客户端已经发送sync包,服务端没有返回ack包,物理链路还没有建立)
    5.向Reactor线程的Selector注册OP_CONNECT状态位,监听服务端的TCPACK应答。
    6.创建Reactor线程,创建多路复用器并启动线程。
    7.多路复用器在线程run方法的无限循环体内轮询准备就绪的Key。
    8.接收connect事件进行处理。
    9.判断连接结果,如果连接成功,注册读事件到多路复用器。
    10.注册读事件到多路复用器。
    11.异步读客户端请求消息到缓存区。
    12.对ByteBuffer进行编解码,如果有半包消息接收缓冲区Reset,继续读取后续的报文,将解码成功的消息封装成Task,投递到业务线程池中。
    13.将POJO对象encode成ByteBuffer,调用SocketChannel的异步write接口,将消息异步发送给客户端。

  4. NIO编程的优点:
    (1)客户端发起的连接操作是异步的,可以通过在多路复用器注册OP_CONNECT等待后续结果,不需要像之前的客户端那样被同步阻塞。
    (2)SocketChannel的读写操作都是异步的,如果没有可读写的数据它不会同步等待,直接返回。
    (3)线程模型的优化:它没有连接句柄数的限制且性能不会随着客户端的增加而线性下降。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值