初识Netty——I/O技术简介

I/O多路复用技术

I/O多路复用技术通过把多个I/O的阻塞复用到同一个 select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求,不需要创建新的额外进程或者线程

I/O多路复用的主要应用场景如下:
◎服务器需要同时处理多个处于监听状态或者多个连接状态的套接字;
◎服务器需要同时处理多种网络协议的套接字

Epoll作出的重大改进:

  1. 支持一个进程打开的 socket 描述符(FD)数量不受限制(仅受限于操作系统的最大文
件句柄数)。
  2. .l/O效率不会随着 FD 数目的增加而线性下降
  3. 使用 mmap 加速内核与用户空间的消息传递,避免不必要的内存复制
  4. epoll的 API 更加简单

NIO入门

认识BIO、NIO、NIO2.0

BIO:通常有一个独立的Acceptor线程负责监听客户端的连接

缺点:缺乏弹性伸缩能力,当线程数膨胀后,系统性能急剧下降

若没有客户端接入,主线程会阻塞在server socket的accept操作上

每当有一个新的客户端请求接入时,服务端必须创建一个新的线程处理新接入的客户端,一个线程只能处理一个客户端连接

 伪异步IO

当有新的客户端接入时,将客户端的 Socket 封装成一个 Task(该任务实现 java.lang.
Runnable 接口)投递到后端的线程池中进行处理(调用线程池的execute方法执行),JDK 的线程池维护一个消息队列和 X
个活跃线程,对消息队列中的任务进行处理。由于线程池可以设置消息队列的大小和最大
线程数,因此,它的资源占用是可控的,无论多少个客户端并发访问,都不会导致资源的
耗尽和岩机。

优点:避免了为每个请求都创建一个独立线程造成的线程资源耗尽问题

缺点:在某些场景下,读取一方的线程也会被阻塞60s,写操作也可能会被阻塞,并不是真正的实现了无阻塞,只是使用了线程池

 NIO:

概念简介:

  1. 缓冲区Buffer:实质上是一个数组,通常是一个字节数组,也可以使用其它类型的数组

  1. 通道channel:像自来水管一样,网络数据通过channel读取和写入,通道可以用于读写或二者同时进行。主要有用于文件读写的filechannel和网络读写的selectablechannel(子类有server socketchannel和socket channel)
  2. 多路复用器selector:多路复用器提供选择已经就绪的任务的能力。selector会不断地轮询注册在其上的Channel,如果某个Channel上面发生读或者写事件,
这个Channel 就处于就绪状态,会被Selector 轮询出来,然后通过 SelectionKey 可以获取就绪Channel 的集合,进行后续的I/O操作。由于JDK 使用了 epoll)代替传
统的 select 实现,所以它并没有最大连接句柄 1024/2048 的限制。这也就意味着只需要一
个线程负责Selector的轮询,就可以接入成千上万的客户端

 NIO服务端主要创建过程

步骤一: 打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端连接的父管道,示例代码如下:
ServerSocketChannel acceptorSvr = ServerSocketChannel.open();


步骤二:绑定监听端口,设置连接为非阻塞模式,示例代码如下
acceptorSvr.socket().bind(new
Inetsocketaddress(Inetaddress.getByName(”工P“),port))


accetorSvr.configureBlocking(false);


步骤三:创建Reactor 线程,创建多路复用器并启动线程,示例代码如下。
,Select○r selector = Selector.○pen();

New Thread(new ReactorTask()).start();

步骤四:将 ServerSocketChannel 注册到 Reactor 线程的多路复用器 Selector 上,监听
ACCEPT事件,示例代码如下


SelectionKey key=acceptorSvr.register(selector,SelectionKey.OP_ACCEPT,
ioHardler);


步骤五:多路复用器在线程run方法的无限循环体内轮询准备就绪的Key,示例代码
如下


int num = selector.select();


Set selectedKeys = selector.selectedKeys()


Iterator it = selectedKeys.iterator();


while(it.hasNext())
selectionKegKeg =(SelectionKey)it.next()﹒
,//·..dealwith I/O event··


步骤六:多路复用器监听到有新的客户端接入,处理新的接入请求,完成 TCP 三次
握手,建立物理链路,示例代码如下


socketChannel channel= svrChannel.accept()


步骤七:设置客户端链路为非阻塞模式,示例代码如下
,channel.confiqureBlocking(false);
channel.socket().setReuseAddress(true);
步骤八:将新接入的客户端连接注册到 Reactor 线程的多路复用器上,监听读操作,
读取客户端发送的网络消息,示例代码如下


SelectionKey key= socketChannel.register(selector,SelectionKeg.0P_READ,
ioHandler);

步骤九:异步读取客户端请求消息到缓冲区,示例代码如下

Int readNumber_=channel.read(receivedBuffer);


步骤十:对 ByteBufer进行编解码,如果有半包消息指针reset,继续读取后续的报文,
将解码成功的消息封装成 Task,投递到业务线程池中,进行业务逻辑编排

步骤十一:将消息异步发送给客户端

SocketChannel.write(buffer)

注意:selectionkey的实例key用来保存用以判断网络事件类型的操作位

 NIO客户端主要创建过程

步骤一:打开socketchannel,绑定客户端本地地址,

步骤二:设置socketchannel为非阻塞模式,同时设置TCP参数,

步骤三:异步连接服务器,

步骤四:判断是否连接成功,如果连接成功,则直接注册读状态位到多路复用器中,
如果当前没有连接成功(异步连接,返回 false,说明客户端已经发送 sync 包,服务端没
有返回 ack 包,物理链路还没有建立)

步骤五:向 Reactor 线程的多路复用器注册OP_CONNECT状态位,监听服务端的 TCP
ACK应答

步骤六:创建 Reactor 线程,创建多路复用器并启动线程

步骤七:多路复用器在线程run方法的无限循环体内轮询准备就绪的 Key

此处注意key是什么

步骤九:判断连接结果,如果连接成功,注册读事件到多路复用器

步骤十:注册读事件到多路复用器

步骤十一:异步读客户端请求消息到缓冲区

步骤十二:对 ByteBuffer 进行编解码,如果有半包消息接收缓冲区 Reset,继续读取
后续的报文,将解码成功的消息封装成 Task,投递到业务线程池中,进行业务逻辑编排

步骤十三:将 POJO 对象 encode 成 ByteBuffer,调用SocketChannel 的异步 write接口,
将消息异步发送给客户端

NIO优点:不会同步阻塞、一个selector线程可以处理成千上万个客户端连接、读写操作是异步的

 AIO编程

◎通过java.util.concurrent.Future 类来表示异步操作的结果;


◎在执行异步操作的时候传入一个 java.nio.channels。
CompletionHandler 接口的实现类作为操作完成的回调

不同IO模型的对比:

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值