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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM