zoukankan      html  css  js  c++  java
  • Netty4.0学习笔记系列之二:Handler的执行顺序(转)

    http://blog.csdn.net/u013252773/article/details/21195593

    Handler在netty中,无疑占据着非常重要的地位。Handler与Servlet中的filter很像,通过Handler可以完成通讯报文的解码编码、拦截指定的报文、统一对日志错误进行处理、统一对请求进行计数、控制Handler执行与否。一句话,没有它做不到的只有你想不到的。

    Netty中的所有handler都实现自ChannelHandler接口。按照输出输出来分,分为ChannelInboundHandler、ChannelOutboundHandler两大类。ChannelInboundHandler对从客户端发往服务器的报文进行处理,一般用来执行解码、读取客户端数据、进行业务处理等;ChannelOutboundHandler对从服务器发往客户端的报文进行处理,一般用来进行编码、发送报文到客户端。

    Netty中,可以注册多个handler。ChannelInboundHandler按照注册的先后顺序执行;ChannelOutboundHandler按照注册的先后顺序逆序执行,如下图所示,按照注册的先后顺序对Handler进行排序,request进入Netty后的执行顺序为:

    基本的概念就说到这,下面用一个例子来进行验证。该例子模拟Client与Server间的通讯,Server端注册了2个ChannelInboundHandler、2个ChannelOutboundHandler。当Client连接到Server后,会向Server发送一条消息。Server端通过ChannelInboundHandler 对Client发送的消息进行读取,通过ChannelOutboundHandler向client发送消息。最后Client把接收到的信息打印出来。

    Server端一共有5个类:HelloServer InboundHandler1 InboundHandler2 OutboundHandler1 OutboundHandler2

    1、HelloServer 代码如下

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. package com.guowl.testmultihandler;  
    2.   
    3. import io.netty.bootstrap.ServerBootstrap;  
    4. import io.netty.channel.ChannelFuture;  
    5. import io.netty.channel.ChannelInitializer;  
    6. import io.netty.channel.ChannelOption;  
    7. import io.netty.channel.EventLoopGroup;  
    8. import io.netty.channel.nio.NioEventLoopGroup;  
    9. import io.netty.channel.socket.SocketChannel;  
    10. import io.netty.channel.socket.nio.NioServerSocketChannel;  
    11.   
    12. public class HelloServer {  
    13.     public void start(int port) throws Exception {  
    14.         EventLoopGroup bossGroup = new NioEventLoopGroup();   
    15.         EventLoopGroup workerGroup = new NioEventLoopGroup();  
    16.         try {  
    17.             ServerBootstrap b = new ServerBootstrap();   
    18.             b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)   
    19.                     .childHandler(new ChannelInitializer<SocketChannel>() {   
    20.                                 @Override  
    21.                                 public void initChannel(SocketChannel ch) throws Exception {  
    22.                                     // 注册两个OutboundHandler,执行顺序为注册顺序的逆序,所以应该是OutboundHandler2 OutboundHandler1  
    23.                                     ch.pipeline().addLast(new OutboundHandler1());  
    24.                                     ch.pipeline().addLast(new OutboundHandler2());  
    25.                                     // 注册两个InboundHandler,执行顺序为注册顺序,所以应该是InboundHandler1 InboundHandler2  
    26.                                     ch.pipeline().addLast(new InboundHandler1());  
    27.                                     ch.pipeline().addLast(new InboundHandler2());  
    28.                                 }  
    29.                             }).option(ChannelOption.SO_BACKLOG, 128)   
    30.                     .childOption(ChannelOption.SO_KEEPALIVE, true);   
    31.   
    32.             ChannelFuture f = b.bind(port).sync();   
    33.   
    34.             f.channel().closeFuture().sync();  
    35.         } finally {  
    36.             workerGroup.shutdownGracefully();  
    37.             bossGroup.shutdownGracefully();  
    38.         }  
    39.     }  
    40.   
    41.     public static void main(String[] args) throws Exception {  
    42.         HelloServer server = new HelloServer();  
    43.         server.start(8000);  
    44.     }  
    45. }  


    2、InboundHandler1

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. package com.guowl.testmultihandler;  
    2.   
    3. import io.netty.channel.ChannelHandlerContext;  
    4. import io.netty.channel.ChannelInboundHandlerAdapter;  
    5.   
    6. import org.slf4j.Logger;  
    7. import org.slf4j.LoggerFactory;  
    8.   
    9. public class InboundHandler1 extends ChannelInboundHandlerAdapter {  
    10.     private static Logger   logger  = LoggerFactory.getLogger(InboundHandler1.class);  
    11.   
    12.     @Override  
    13.     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
    14.         logger.info("InboundHandler1.channelRead: ctx :" + ctx);  
    15.         // 通知执行下一个InboundHandler  
    16.         ctx.fireChannelRead(msg);  
    17.     }  
    18.   
    19.     @Override  
    20.     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {  
    21.         logger.info("InboundHandler1.channelReadComplete");  
    22.         ctx.flush();  
    23.     }  
    24. }  

    3、InboundHandler2

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. package com.guowl.testmultihandler;  
    2.   
    3. import io.netty.buffer.ByteBuf;  
    4. import io.netty.channel.ChannelHandlerContext;  
    5. import io.netty.channel.ChannelInboundHandlerAdapter;  
    6.   
    7. import org.slf4j.Logger;  
    8. import org.slf4j.LoggerFactory;  
    9.   
    10. public class InboundHandler2 extends ChannelInboundHandlerAdapter {  
    11.     private static Logger   logger  = LoggerFactory.getLogger(InboundHandler2.class);  
    12.   
    13.     @Override  
    14.     // 读取Client发送的信息,并打印出来  
    15.     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
    16.         logger.info("InboundHandler2.channelRead: ctx :" + ctx);  
    17.         ByteBuf result = (ByteBuf) msg;  
    18.         byte[] result1 = new byte[result.readableBytes()];  
    19.         result.readBytes(result1);  
    20.         String resultStr = new String(result1);  
    21.         System.out.println("Client said:" + resultStr);  
    22.         result.release();  
    23.   
    24.         ctx.write(msg);  
    25.     }  
    26.   
    27.     @Override  
    28.     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {  
    29.         logger.info("InboundHandler2.channelReadComplete");  
    30.         ctx.flush();  
    31.     }  
    32.   
    33. }  

    4、OutboundHandler1

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. package com.guowl.testmultihandler;  
    2.   
    3. import io.netty.buffer.ByteBuf;  
    4. import io.netty.channel.ChannelHandlerContext;  
    5. import io.netty.channel.ChannelOutboundHandlerAdapter;  
    6. import io.netty.channel.ChannelPromise;  
    7.   
    8. import org.slf4j.Logger;  
    9. import org.slf4j.LoggerFactory;  
    10.   
    11. public class OutboundHandler1 extends ChannelOutboundHandlerAdapter {  
    12.     private static Logger   logger  = LoggerFactory.getLogger(OutboundHandler1.class);  
    13.     @Override  
    14.     // 向client发送消息  
    15.     public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {  
    16.         logger.info("OutboundHandler1.write");  
    17.         String response = "I am ok!";  
    18.         ByteBuf encoded = ctx.alloc().buffer(4 * response.length());  
    19.         encoded.writeBytes(response.getBytes());  
    20.         ctx.write(encoded);  
    21.         ctx.flush();  
    22.     }  
    23.       
    24.       
    25. }  

    5、OutboundHandler2

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. package com.guowl.testmultihandler;  
    2.   
    3. import io.netty.channel.ChannelHandlerContext;  
    4. import io.netty.channel.ChannelOutboundHandlerAdapter;  
    5. import io.netty.channel.ChannelPromise;  
    6.   
    7. import org.slf4j.Logger;  
    8. import org.slf4j.LoggerFactory;  
    9.   
    10. public class OutboundHandler2 extends ChannelOutboundHandlerAdapter {  
    11.     private static Logger   logger  = LoggerFactory.getLogger(OutboundHandler2.class);  
    12.       
    13.     @Override  
    14.     public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {  
    15.         logger.info("OutboundHandler2.write");  
    16.         // 执行下一个OutboundHandler  
    17.         super.write(ctx, msg, promise);  
    18.     }  
    19. }  


    Client端有两个类:HelloClient  HelloClientIntHandler

    1、HelloClient  

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. package com.guowl.testmultihandler;  
    2.   
    3. import io.netty.bootstrap.Bootstrap;  
    4. import io.netty.channel.ChannelFuture;  
    5. import io.netty.channel.ChannelInitializer;  
    6. import io.netty.channel.ChannelOption;  
    7. import io.netty.channel.EventLoopGroup;  
    8. import io.netty.channel.nio.NioEventLoopGroup;  
    9. import io.netty.channel.socket.SocketChannel;  
    10. import io.netty.channel.socket.nio.NioSocketChannel;  
    11.   
    12. public class HelloClient {  
    13.     public void connect(String host, int port) throws Exception {  
    14.         EventLoopGroup workerGroup = new NioEventLoopGroup();  
    15.   
    16.         try {  
    17.             Bootstrap b = new Bootstrap();  
    18.             b.group(workerGroup);  
    19.             b.channel(NioSocketChannel.class);  
    20.             b.option(ChannelOption.SO_KEEPALIVE, true);  
    21.             b.handler(new ChannelInitializer<SocketChannel>() {  
    22.                 @Override  
    23.                 public void initChannel(SocketChannel ch) throws Exception {  
    24.                     ch.pipeline().addLast(new HelloClientIntHandler());  
    25.                 }  
    26.             });  
    27.   
    28.             // Start the client.  
    29.             ChannelFuture f = b.connect(host, port).sync();  
    30.             f.channel().closeFuture().sync();  
    31.         } finally {  
    32.             workerGroup.shutdownGracefully();  
    33.         }  
    34.     }  
    35.   
    36.     public static void main(String[] args) throws Exception {  
    37.         HelloClient client = new HelloClient();  
    38.         client.connect("127.0.0.1", 8000);  
    39.     }  
    40. }  

    2、HelloClientIntHandler

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. package com.guowl.testmultihandler;  
    2.   
    3. import io.netty.buffer.ByteBuf;  
    4. import io.netty.channel.ChannelHandlerContext;  
    5. import io.netty.channel.ChannelInboundHandlerAdapter;  
    6.   
    7. import org.slf4j.Logger;  
    8. import org.slf4j.LoggerFactory;  
    9.   
    10. public class HelloClientIntHandler extends ChannelInboundHandlerAdapter {  
    11.     private static Logger   logger  = LoggerFactory.getLogger(HelloClientIntHandler.class);  
    12.     @Override  
    13.     // 读取服务端的信息  
    14.     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
    15.         logger.info("HelloClientIntHandler.channelRead");  
    16.         ByteBuf result = (ByteBuf) msg;  
    17.         byte[] result1 = new byte[result.readableBytes()];  
    18.         result.readBytes(result1);  
    19.         result.release();  
    20.         ctx.close();  
    21.         System.out.println("Server said:" + new String(result1));  
    22.     }  
    23.     @Override  
    24.     // 当连接建立的时候向服务端发送消息 ,channelActive 事件当连接建立的时候会触发  
    25.     public void channelActive(ChannelHandlerContext ctx) throws Exception {  
    26.         logger.info("HelloClientIntHandler.channelActive");  
    27.         String msg = "Are you ok?";  
    28.         ByteBuf encoded = ctx.alloc().buffer(4 * msg.length());  
    29.         encoded.writeBytes(msg.getBytes());  
    30.         ctx.write(encoded);  
    31.         ctx.flush();  
    32.     }  
    33. }  

    server端执行结果为:

    在使用Handler的过程中,需要注意:

    1、ChannelInboundHandler之间的传递,通过调用 ctx.fireChannelRead(msg) 实现;调用ctx.write(msg) 将传递到ChannelOutboundHandler。

    2、ctx.write()方法执行后,需要调用flush()方法才能令它立即执行。

    3、ChannelOutboundHandler 在注册的时候需要放在最后一个ChannelInboundHandler之前,否则将无法传递到ChannelOutboundHandler。

  • 相关阅读:
    172. Factorial Trailing Zeroes
    96. Unique Binary Search Trees
    95. Unique Binary Search Trees II
    91. Decode Ways
    LeetCode 328 奇偶链表
    LeetCode 72 编辑距离
    LeetCode 226 翻转二叉树
    LeetCode 79单词搜索
    LeetCode 198 打家劫舍
    LeetCode 504 七进制数
  • 原文地址:https://www.cnblogs.com/jiligalaer/p/3972491.html
Copyright © 2011-2022 走看看