Netty 学习笔记

来源:互联网 发布:as3 调用js 编辑:程序博客网 时间:2024/06/06 03:25

            本文主要记录学习Netty 的过程中的各种问题以及自己的心得记录


一、先总体认识一下Netty 用到的组件以及在整个架构中是如何协调工作的,必不可少的组件包括:



BootStrap/ServerBootStrap       分别对应客户端以及服务器端,用来配置整个Netty 程序,串联各个组件,一个Netty 程序也是由这部分开启


Handler 为了支持各种协议和处理数据的方式,支持协议主要说的是解析bytebuf到可以解析的说句,handler主要用来处理各种事件,包括连接,数据接收,异常或者数据装换等,在Netty 中,通讯的双方建立连接后,会将数据按照ByteBuf的方式进行传输,也就是说传输都是字节,用的抽象形式就是ByteBuf,例如http协议中,服务端就是通过Netty 提供的HttpRequestDecoder对输入的ByteBuf字节数据流进行处理,转换为http对象,同时在输出的时候,通过HttpResponseEncoder将输出的http对象编码成ByteBuf字节数据流输出,同理客户端使用的是HttpRequestEncoder以及HttpResponseDecoder


EventLoop的目的是用来为channel处理IO操作,采用事件通知机制,一个EventLoop可以为多个Channel服务, EventLoopGoop中包括多个EventLoop,Channel就是一个Socket连接,或者其它和IO操作相关的组件


Future,在Netty 中所有的IO操作都是异步的,因此,在调用方法后不能立刻得到正确或者错误的返回,但是可以通过执行sync方法,等待到方法的返回,或者直接注册监听,通过回调的方式,Netty 会在操作执行完成后自动触发回调,所有的操作都会返回一个ChannelFuture



Netty 是一个非阻塞的,事件驱动的,网络编程框架,Netty 也会用线程来处理IO事件,一个Channel对应一个EventLoop,一个EventLoop会对应多个Channel,一个EventLoop对应一个线程,也就是一个线程可以处理多个Channel ,这也就是JAVA NIO的核心设计





如上图,很形象的表达了Channel是如何注册到EventLoop的,当一个连接到达,Netty 会注册一个channel,这个channel就表示客户端和服务端的连接,Netty 会使用EventLoopGroup(bossGroup)从另外一个EventLoopGroup(workerGroup)中分配一个EventLoop来绑定到channel,当然可以看到是循环从workerGroup中取出来EventLoop,所以这就是为什么一个EventLoop会对应多个Channel,在这个channel的整个生命周期过程中,都会由这个EventLoop来为它服务,而这个EventLoop实际上就是一个无线循环的事件驱动线程


EventLoop实际上继承了ScheduledExecutorService接口,在java的concurrent包里面是提供了ScheduledExecutorService接口的实现,而Netty 框架同样实现了ScheduledExecutorService接口,但是是内部代码实现了接口,同样提供定时任务的执行,所以说EventLoop本身是支持定时任务的执行,不是依靠的jdk的实现(不是注入jdk的ScheduledExecutorService的实现),而是自己编写的实现,通过ScheduledExecutorService接口能明确该类具有定时任务的功能


客户端的Bootstrap 一般用一个EventLoopGroup, 而服务端的ServerBootStrap会用到两个,第一个EventLoopGroup专门负责分配eventLoop给channel,负责两者关系的绑定,而第二个EventLoopGroup用来处理channel后续的整个生命周期的通信过程。(真正处理的是EventLoopGroup中的eventLoop),如果服务端仅由一个EventLoopGroup来处理所有请求和连接,在并发量很大的情况下,这个EventLoopGroup有可能会忙于处理已经接收到的连接而不能及时处理新的连接请求,如果使用两个EventLoopGroup,使用专门的线程来处理连接过程,不会导致请求超时的情况,大大提高了并发处理能力,由于eventLoop的事件通知机制,减少了BIO模型下每个线程为单独的socket的等待时间


在使用Netty 开发应用程序的时候,最重要的就是ChannelHandler,数据在一个ChannlePipleline,其中需要完成的编码解码,用户操作等都是channelHandler,数据流都会经过每一个channlehandler并且被这个handler处理,ChannelHandler分为两种ChannelOutboundHandler和ChannleInboundHandler,这两个接口分别对应了两个数据流向


如果数据是从外部流入应用程序,这是inbound


如果数据是从应用程序流到外部,这是outbound


一个channelpipeline可以将两种handler混合在一起,数据写进来的时候,传到第一个inboundhandler,再继续下一个inbound

数据写出去的时候,从最后一个outhandler,再继续从前一个outhandler


在channelpipeline中是混合了两种handler,因为handler实现的接口不同,一个是处理入,一个是处理出,所以对于inbound event,Netty 会自动跳过outboundhandler,对于outbound event,Netty 会自动跳过inboundhandler


三种最常用的ChannelHandler


Encoders和Decoders


因为在网络传输时只能传输字节流,因为,在发送数据之前,必须将应用程序内部的message转换为bytes,对应的,在接受到数据后,必须将接受到的bytes转换成message,这个message可以是String,这样就需要StringEncoder和StringDecoder,如果是Java对象,则需要编写对应的encoder和decoder


decoder-解码,将bytes解析称为可以认识的对象,通过channelreader方法,在这个方法中调用具体的decode方法解码传递过来的字节流,再通过调用

channelHandlerContext.fireChannelRead方法将解码后的对象传递给下一个handler


下一个handler就是应用程序最关心的逻辑handler了,真正的业务逻辑则是处理这个接受到的数据,Netty 提供一个最常用的基础类SimpleChannelInboundHandler<T>,

其中这个泛型T就是这个业务逻辑Handler需要处理的数据类型(上一个解码的handler已经处理好了),消息达到这个handler后,Netty 框架会自动调用这个Handler的

channelRead0(ChannelHandlerContext, T)方法, T就是解码后传递过来的数据,所以应用程序只需要关注如何在这个handler里面编写业务逻辑了。




0 0
原创粉丝点击