认识Netty

来源:互联网 发布:iphone图片查看软件 编辑:程序博客网 时间:2024/05/27 20:05

        Netty的特性:

Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序,整体来看其包含了以下内容:

  1. 实现了自有的、丰富的Buffer数据结构,彻底解决java NIO ByteBuffer的问题,满足开发者的日常需求。
  2. 统一的阻塞和非阻塞的IO协议API
  3. 基于灵活、可扩展的事件驱动模型
  4. 为快速开发提供了丰富的组件和协议支持

       Netty普通使用一般是通过BootStrap来启动,BootStrap主要分为两类:

       1.面向连接(TCP)的BootStrap(ClientBootStrap和ServerBootstrap),

       2.非面向连接(UDP) 的(ConnectionlessBootstrap)。

      

Netty的应用

        面向连接的Netty服务端客户端使用,第一步:实例化一个BootStrap,并且通过构造方法指定一个ChannelFactory实现,第二步:向bootstrap实例注册一个自己实现的ChannelPipelineFactory,第三步:如果是服务器端,bootstrap.bind(new InetSocketAddress(port)),然后等待客户端来连接,如果是客户端,bootstrap.connect(new InetSocketAddress(host,port))取得一个future,这个时候Netty会去连接远程主机,在连接完成后,会发起类型为 CONNECTED的ChannelStateEvent,并且开始在你自定义的Pipeline里面流转,如果你注册的handler有这个事件的响应方法的话那么就会调用到这个方法。在此之后就是数据的传输了。这些可以通过netty Example去了解。下面是一个Netty的server端例子:

        

public static void bootServer() { // More terse code to setup the server ServerBootstrap bootstrap = new ServerBootstrap(   new NioServerSocketChannelFactory(     Executors.newCachedThreadPool(),     Executors.newCachedThreadPool()));  // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() {  public ChannelPipeline getPipeline() throws Exception {   return Channels.pipeline(    new ObjectDecoder(ClassResolvers.cacheDisabled(getClass().getClassLoader())),    new DateHandler()   );  }; });  // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress("0.0.0.0", 8080)); slog("Listening on 8080");} static class DateHandler extends SimpleChannelHandler { public void messageReceived(ChannelHandlerContext ctx,MessageEvent e) throws Exception {  Date date = (Date)e.getMessage();  // Here's the REALLY important business service at the end of the pipeline  slog("Hey Guys !  I got a date ! [" + date + "]");  // Huh ?  super.messageReceived(ctx, e); }  }

        Netty整体架构很清晰的分成2个部分,ChannelFactory 和ChannelPipelineFactory,前者主要生产网络通信相关的Channel实例和ChannelSink实例,Netty提供的 ChannelFactory实现基本能够满足绝大部分用户的需求,当然你也可以定制自己的ChannelFactory,后者主要关注于具体传输数据的处理,同时也包括其他方面的内容,比如异常处理等等,只要是你希望的,你都可以往里添加相应的handler,一般 ChannelPipelineFactory由用户自己实现,因为传输数据的处理及其他操作和业务关联比较紧密,需要自定义处理的handler。

       

Netty提供了NIO与BIO(OIO)两种模式处理这些逻辑,其中NIO主要通过一个BOSS线程处理等待链接的接入,若干个WORKER线程(从worker线程池中挑选一个赋给Channel实例,因为Channel实例持有真正的 java网络对象)接过BOSS线程递交过来的CHANNEL进行数据读写并且触发相应事件传递给pipeline进行数据处理,而BIO(OIO)方式服务器端虽然还是通过一个BOSS线程来处理等待链接的接入,但是客户端是由主线程直接connect,另外写数据C/S两端都是直接主线程写,而数据读操作是通过一个WORKER 线程BLOCK方式读取(一直等待,直到读到数据,除非channel关闭)。

网络动作归结到最简单就是服务器端bind->accept->read->write,客户端 connect->read->write,一般bind或者connect后会有多次read、write。这种特性导致,bind,accept与read,write的线程分离,connect与read、write线程分离,这样做的好处就是无论是服务器端还是客户端吞吐量将有效增大,以便充分利用机器的处理能力,而不是卡在网络连接上,不过一旦机器处理能力充分利用后,这种方式反而可能会因为过于频繁的线程切换导致性能损失而得不偿失,并且这种处理模型复杂度比较高。

采用什么样的网络事件响应处理机制对于网络吞吐量是非常重要的,Netty采用的是标准的SEDA(Staged Event-Driven Architecture)架构[http://en.wikipedia.org/wiki/ Staged_event-driven_architecture],其所设计的事件类型,代表了网络交互的各个阶段,并且在每个阶段发生时,触发相应事件交给初始化时生成的pipeline实例进行处理。事件处理都是通过Channels类的静态方法调用开始的,将事件、channel传递给 channel持有的Pipeline进行处理,Channels类几乎所有方法都为静态,提供一种Proxy的效果(整个工程里无论何时何地都可以调用其静态方法触发固定的事件流转,但其本身并不关注具体的处理流程)。

Channels部分事件流转静态方法
1.fireChannelOpen 2.fireChannelBound 3.fireChannelConnected 4.fireMessageReceived 5.fireWriteComplete 6.fireChannelInterestChanged
7.fireChannelDisconnected 8.fireChannelUnbound 9.fireChannelClosed 10.fireExceptionCaught 11.fireChildChannelStateChanged

Netty提供了全面而又丰富的网络事件类型,其将java中的网络事件分为了两种类型Upstream和Downstream。一般来说,Upstream类型的事件主要是由网络底层反馈给Netty的,比如messageReceived,channelConnected等事件,而Downstream类型的事件是由框架自己发起的,比如bind,write,connect,close等事件。





原创粉丝点击