Netty的流程和范例(自主拼凑研发)

Netty的流程和范例(自主拼凑研发)

 

一,netty的原理

1.要了解netty,就要了解一下三个概念:nio,bio,aio

Bio:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情就会造成不必要的线程开销,当然可以通过线程池机制改善。它适用于连接数目小的框架,Bio适合流量很高的应用,如文件传输

例:

InputStream is = new FileInputStream("input.bin");
int byte = is.read(); // 当前线程等待结果到达直至错误

再比如Tomcat是一个Web服务器,它是采取一个请求一个线程,当有1000客户端时,会耗费很多内存。通常一个线程将花费 256kb到1mb的stack空间。

 

Nio:同步并阻塞,NIO相当于是线程池方式的BIO服务器实现模式为一个请求一个线程,即客户端发送的的连接请求都会注册到多路复合器(轮询器)上,轮询到I/O连接就启动一个线程处理。

nio类库是jdk1.4中引入的。同步阻塞IO是以流的方式处理数据NIO是基于块(Block)的,它以块为基本单位处理数据 (硬盘上存储的单位也是按Block来存储,这样性能上比基于流的方式要好一些)

 

例:

while (true) {
selector.select(); // 从多个通道请求事件
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectorKey key = (SelectionKey) it.next();
handleKey(key);
it.remove();
}

所以NIO适用于连接多,且等待时间较短的架构,比如聊天

Aio(NIO.2):异步非阻塞,服务器实现模式为一个请求一个线程,客户端I/O请求都是OS(操作系统)先完成了再通知服务器应用启动线程进行处理,所以比较适合连接数目多且连接时间长(重复操作)的架构,比如相册服务器。

 

2.Bio和nio的比较图

 

 

 

.netty的工作机制

流程图:

 

1. bossGroup线程和workerGroup线程

bossGroup线程:由这个线程池提供的线程是boss种类的,用于创建、连接、绑定socket,然后把这些socket传 给worker线程池。在服务器端每个监听的socket都 有一个boss线 程来处理。在客户端,只有一个boss线程来处理所有的socket。

workerGroup线程:Worker线 程执行所有的异步I/O。 他们不是通用的线程,开发人员需要注意不要把与其不同的任务赋给线程,这可能导致线程被阻塞、无法处理他们真正关心的任务,反过来会导致死锁和一些莫名其妙的性能问题。

 

ServerBootstrap是一个对服务端做配置和启动的类

EventLoopGroup它是继承于ScheduledExecutorService线程池接口的接口,而NioEventLoopGroup就是它的一个实现类。在服务器启动时,创建两个线程池,xi惯上一个叫bossGroup,一个叫workGroup,如果在构造函数中不指定创建的线程数量,会默认创建当前cpu个数的2倍个。

ChannelInitializer当一个链接建立时,我们需要知道怎么来接收或者发送数据,当然,我们有各种各样的Handler实现来处理它,那么ChannelInitializer便是用来配置这些Handler,它会提供一个ChannelPipeline,并把Handler加入到ChannelPipeline。

关系:

可以这么说,ServerBootstrap监听的一个端口对应一个boss线程,它们一 一对应。比如你需要netty监听80和443端口,那么就会有两个boss线程分别负责处理来自两个端口的socket请求。在boss线程接收了socket连接请求后,会产生一个channel(一个打开的socket对应一个打开的channel),并把这个channel交给ServerBootstrap初始化时指定的ChannelInitializer来处理,boss线程则继续处理socket的请求。从worker线程池中找出一个worker线程来继续处理这个请求。

如果是Oio的话,那个这个channel上所有的socket消息,从开始到channel(socket)关闭,都只由这个特定的worker来处理,也就是说一个打开的socket对应一个指定的worker线程,这个worker线程在socket没有关闭的情况下,也只能为这个socket处理消息,无法服务其他socket。

 

当一个连接到达,Netty会注册一个channel,然后EventLoopGroup(worker)会分配一个EventLoop绑定到这个channel,在这个channel的整个生命周期过程中,都会由绑定的这个EventLoop来为它服务,而这个EventLoop就是一个线程。

 

2.Buffer(内存):

Netty的缓存分为堆内存(HeapByteBuf)和直接内存(DirectByteBuf)缓冲区。堆内存缓冲区的特点是分配和回收速度快,可以被JVM自动回收,缺点是进行Socket的IO读写,需要额外进行一次内存复制,将堆内存对应的缓冲区复制到内核中,性能会有一定程度的下降;直接内存缓冲区的特点是非堆内存,,它在堆外进行内存分配,相比于堆内存,它的分配和回收速度会慢一些,但是将它写入或者从Socket Channel中读取时,由于少了一次内存复制,速度比堆内存快。

 

3. Channel

Netty是一个线程服务于很多请求,当从Java NIO获得一个Selector事件,将激活通道Channel。

包括了网络的读,写,客户端发起连接,主动关闭连接,获取对方网络地址等,封装了Socket的操作,当有Socket操作发生时,会触发事件相应操作如:channelRead、channelReadComplete、exceptionCaught等方法

 

 

 

 

4.Pipeline:

可以看作是一条流水线,原始的原料(字节流)进来,经过加工,最后输出

 

channel中的核心组件包括:

 

pipeline中保存了channel的引用,创建完pipeline之后,整个pipeline是这个样子的

 

 

pipeline中的每个节点是一个ChannelHandlerContext对象,每个context节点保存了它包裹的执行器 ChannelHandler 执行操作所需要的上下文,其实就是pipeline,因为pipeline包含了channel的引用,可以拿到所有的context信息。

 

pipline里添加节点:

ChannelPipeline p = ch.pipeline();

p.addLast(new ChannelInboundHandler

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值