Netty框架入门

一、概述
    Netty是由JBOSS提供的一个java开源框架。
    Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
 
二、体系结构图
   
三、Netty的核心结构
    Netty是典型的Reactor模型结构,在实现上,Netty中的Boss类充当mainReactor,NioWorker类充当subReactor(默认NioWorker的个数是当前服务器的可用核数)。
    在处理新来的请求时,NioWorker读完已收到的数据到ChannelBuffer中,之后触发ChannelPipeline中的ChannelHandler流。
    Netty是事件驱动的,可以通过ChannelHandler链来控制执行流向。因为ChannelHandler链的执行过程是在subReactor中同步的,所以如果业务处理handler耗时长,将严重影响可支持的并发数。
   
四、客户端和服务器端通信Demo

    Server-main:

ChannelFactory factory = new  NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
ServerBootstrap bootstrap = new  ServerBootstrap(factory);
bootstrap.setPipelineFactory( new  ChannelPipelineFactory(){ 
     @Override
     public  ChannelPipeline getPipeline() throws Exception {
         return  Channels.pipeline( new  TimeServerHandler());
     }
});
bootstrap.setOption( "child.tcpNoDelay" , true );
bootstrap.setOption( "child.keepAlive" , true );
bootstrap.bind( new  InetSocketAddress(1989));

    ChannelFactory 是一个创建和管理Channel通道及其相关资源的工厂接口,它处理所有的I/O请求并产生相应的I/O ChannelEvent通道事件。这个工厂并自己不负责创建I/O线程。应当在其构造器中指定该工厂使用的线程池,这样我们可以获得更高的控制力来管理应用环境中使用的线程。

    ServerBootstrap 是一个设置服务的帮助类。设置了一个继承自ChannelPipelineFactory的匿名类,用来作为ChannelPipeline通道,当服务器接收到一个新的连接,一个新的ChannelPipeline管道对象将被创建,并且所有在这里添加的ChannelHandler对象将被添加至这个新的ChannelPipeline管道对象。

     Server-Handler:
@Override
public  void  channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws  Exception {
     //TimeServer   
     Channel ch = e.getChannel();
     ChannelBuffer time = ChannelBuffers.buffer( 8 );
     time.writeLong(System.currentTimeMillis());
     ChannelFuture future = ch.write(time); 
     future.addListener( new  ChannelFutureListener() {       
         @Override      
         public  void  operationComplete(ChannelFuture arg0) throws  Exception {       
             Channel ch = arg0.getChannel();
             ch.close();
         }
     });
}
    Handler中是我们的业务逻辑,在Server的Handler里重载了channelConnected方法,当收到连接请求时,将当前服务器时间写入到Channel,并且在写完后触发关闭Channel。

     Client-main:
ChannelFactory factory = new  NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
ClientBootstrap bootstrap = new  ClientBootstrap(factory);
bootstrap.setPipelineFactory( new  ChannelPipelineFactory() {
     @Override  
     public  ChannelPipeline getPipeline() throws  Exception {
         return  Channels.pipeline( new  TimeClientHandler());
     }
});
bootstrap.setOption( "tcpNoDelay" , true );
bootstrap.setOption( "keepAlive" , true );
bootstrap.connect( new  InetSocketAddress( "127.0.0.1" , 1989 ));
    Client端初始化Netty的过程和Server类似,只是将使用到的类替换为Client端的。
     Client-Handler:
@Override
public  void  messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws  Exception {
     ChannelBuffer buf = (ChannelBuffer)e.getMessage();
     Long currentTimeMillis = buf.readLong();
     System.out.println( new  Date(currentTimeMillis));
     e.getChannel().close();
}
    Client端的Handler里,我们将从服务器端接收到的信息转换为时间打印到控制台。
 
五、基于HTTP协议的服务器端实现
//HttpServerPipelineFactory.java
public  class  HttpServerPipelineFactory implements  ChannelPipelineFactory {
     @Override
     public  ChannelPipeline getPipeline() throws  Exception {
         ChannelPipeline pipeline = Channels.pipeline();
         pipeline.addLast( "decoder" , new  HttpRequestDecoder());
         pipeline.addLast( "encoder" , new  HttpResponseEncoder());
         pipeline.addLast( "handler" , new  HttpServerHandler());
         return  pipeline;
     }
}
    新建一个HttpServerPipelineFactory类,在getPipeline()方法中添加了对Http协议的支持。
// HttpServer.java
bootstrap.setPipelineFactory( new  HttpServerPipelineFactory());
    在Server里面使用我们新建的HttpServerPipelineFactory。
//HttpServerHandler.java
public  void  messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws  Exception {
     DefaultHttpRequest defaultHttpRequest = (DefaultHttpRequest)e.getMessage();
     String uri = defaultHttpRequest.getUri();
     byte [] data = defaultHttpRequest.getContent().array();
     String content = URLDecoder.decode( new  String(data), "utf-8" ).trim();
     System.out.println(uri+ "|" +content);
     Channel ch = e.getChannel();
     HttpResponse response = new  DefaultHttpResponse(HTTP_1_1, OK);
     ChannelBuffer buffer = new  DynamicChannelBuffer( 2048 );
     buffer.writeBytes( "200" .getBytes( "UTF-8" ));
     response.setContent(buffer);
     response.setHeader( "Content-Type" , "text/html;charset=UTF-8" );
     response.setHeader( "Content-Length" , response.getContent().writerIndex());
     if  (ch.isOpen() && ch.isWritable()) {  
         ChannelFuture future = ch.write(response); 
         future.addListener( new  ChannelFutureListener() {       
             @Override      
             public  void  operationComplete(ChannelFuture arg0) throws  Exception {           
                 Channel ch = arg0.getChannel();        
                 ch.close();
             }  
         });
     }
}
    在Handler里面我们可以直接拿到DefaultHttpRequest类型的对象,因为Netty已经用HttpRequestDecoder帮我们把接受到的数据都转换为HttpRequest类型了。
    使用了多个Handler后,通过下图,Netty的事件驱动就可以被很好的理解了:
  
    UpstreamEvent是被UpstreamHandler们自底向上逐个处理,DownstreamEvent是被DownstreamHandler们自顶向下逐个处理,这里的上下关系就是向ChannelPipeline里添加Handler的先后顺序关系。
 
六、总结
    Netty是一个简单却不失强大的架构。这个架构由三部分组成——缓冲(Buffer)、通道(Channel)、事件模型(Event Model)——所有的高级特性都构建在这三个核心组件之上。
 
七、深入学习
    http://netty.io/
    https://github.com/netty/netty
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值