Netty 4 ChannelHandler和ChannelPipeline

Netty 4 ChannelHandler和ChannelPipeline

相關的接口:
1.ChannelHandler
   對應的ChannelInboundHandler和ChannelOutboundHandler
   對應的ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter
2.ChannelPipeline
3.ChannelHandlerContext


ChannelHandler
ChannelHandler是開發人員應用的主要實現組件,他充當了所有入站數據和出站數據的處理。並且ChannelHandler的方法是由網絡觸發的。     一般會將應用程序的業務邏輯存放在一個或者多個ChannelInboundHandler中。
實際應用中:在ChannelHandler中可實現幾乎所有類型的任務,比如數據格式的轉換,或者處理轉換過程中所拋出的異常。

ChannelInboundHandler負責處理入站數據,ChannelOutboundHandler負責出站數據。
當某個ChannelInboundHandler的實現重寫channelRead方法的時候,需要我們顯式的釋放與池化ByteBuf實例相關的內存。
如果是實現自SimpleChannelInboundHandler<Object>不需要顯式的釋放資源。因爲SimpleChannelInboundHandler會自動釋放資源。

public void channelRead(ChannelHandlerContext ctx,Object msg){
     ReferenceCountUtil.release(msg);
}

注意:在實現ChannelHandler中channelRead的方法中,可以執行任何業務,但是要求不要阻塞當前的IO線程,也就是說不要在channelRead方法中執行長耗時的任務。
1.當前的IO線程是啥? workGroup中定義的EventLoop分配的線程
2.爲什麼會導致IO線程阻塞? 因爲在Channel的聲明週期中所有的任務都會由註冊的EventLoop去完成。如果請求的業務處理消耗大量時間,會導致EventLoop被這個任務獨佔,而其他註冊到這個EventLoop中的Channel的讀寫任務會被阻塞。
3.如何解決? 如果必須阻塞調用或者執行長時間任務,可以使用一個專門的EventExecutor。

ChannelPipeline
ChannelPipeline爲ChannelHandler提供了容器,多個ChannelHandler還在ChannelPipeline中按照定義的順序傳播。當一個Channel被創建的時候,他會被自動分配專屬的ChannelPipeline。

當存在一個入站事件,他會從ChannelPipeline中的頭部開始運動,從第一個ChannelInboundHandler開始處理,在這個過程中可能會修改數據,或者將數據格式轉換爲下一個ChannelInboundHandler希望得到的數據,這個取決於ChannelHandler的功能。最終會將數據傳遞到ChannelPipeline的尾端。

出站時間和入站類似,不過是從ChannelPipeline的尾端開始,先前傳遞數據直到頭部,之後就是將數據傳輸到網絡成(Socket)。



ChannelHandlerContext
當ChannelHandler在被分配到ChannelPipeline的時候,他將會分配到一個ChannelHandlerContext,通過這個對象可以將ChannelHandler和CHannelPipeline相互關聯。通過通過ctx獲取Pipeline、獲取ChannelHandler、獲取底層的Channel。最主要的是ctx可以用於寫入數據。

Netty中有兩種發送消息的方式,一個是直接寫入Channel中,第二個是寫入和ChannelHandler相關的ChannelHandlerContext中。
前者:消息從ChannelPipeline 的尾端開始流動,
後者:消息從ChannelPipeline的下一個ChannelHandler流動

public void start(int port) throws Exception {
     EventLoopGroup bossGroup = new NioEventLoopGroup(1);
     EventLoopGroup workerGroup = new NioEventLoopGroup(nettyThread);
     try {
           ServerBootstrap b = new ServerBootstrap();
           b.group(bossGroup, workerGroup)
           .channel(NioServerSocketChannel.class) // (3)
        .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        // server端發送的是httpResponse,所以要使用HttpResponseEncoder進行編碼
                        ch.pipeline().addLast(new HttpResponseEncoder());
                        // server端接收到的是httpRequest,所以要使用HttpRequestDecoder進行解碼
                        ch.pipeline().addLast(new HttpRequestDecoder());

                        ch.pipeline().addLast(new HttpObjectAggregator(nettyLength));
                        ch.pipeline().addLast(new HttpServerInboundHandler());
                    }
                }).option(ChannelOption.SO_BACKLOG, 128) // (5)
        .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

           ChannelFuture f = b.bind(port).sync();
           f.channel().closeFuture().sync();
     } finally {
           workerGroup.shutdownGracefully();
           bossGroup.shutdownGracefully();
     }
}


liukeng
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章