关闭

Netty:Handler的执行顺序

105人阅读 评论(0) 收藏 举报
分类:

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 new ServerBootstrap();   
  18.             b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class  
  19.                     .childHandler(new ChannelInitializer()   
  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 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 new Bootstrap();  
  18.             b.group(workerGroup);  
  19.             b.channel(NioSocketChannel.class);  
  20.             b.option(ChannelOption.SO_KEEPALIVE, true);  
  21.             b.handler(new ChannelInitializer()  
  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 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。

0
0
查看评论

nio学习之netty入门(2)---netty中handler的执行顺序

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

关于Netty Pipeline中Handler的执行顺序问题

最近在学习Netty框架,根据官网
  • wgyvip
  • wgyvip
  • 2014-05-12 17:29
  • 4354

netty的Pipeline里面的执行定制模型顺序问题

最近在看netty的书,在处理粘包问题的时候,我按照上面的代码执行,但是粘包问题还是存在,而且有时候还不只是粘包的问题,还会报错。 后来发现我的Pipeline没有按照他的顺序,我开始的时候以为这个是随便顺便的,后来发现顺序不对还会出问题。 然后自己就往里面挖了一下,不是很深,发现他其实是一个链表的...
  • BB_huiyi
  • BB_huiyi
  • 2016-11-23 18:20
  • 1028

netty中的ChannelHandler

本文主要介绍以下几个相关类: • ChannelPipeline • ChannelHandlerContext • ChannelHandler • Inbound vs outbound(入站和出站)接受客户端的连接和创建连接只是应用程序中的一步,更加重要的还是处理传入传...
  • u010853261
  • u010853261
  • 2017-01-16 16:38
  • 3939

Netty:Bootstrap的handler和childHandler

介绍Bootstrap中handler和childHandler的区别
  • bdmh
  • bdmh
  • 2015-11-19 15:16
  • 9639

Netty Sharable Handler 使用是私有变量

Netty Sharable Handler 使用是私有变量netty中Sharable handler的定义如下 http://netty.io/4.0/api/io/netty/channel/ChannelHandler.Sharable.html我们不用每次都创建handler,例如下面的...
  • mlkiller
  • mlkiller
  • 2015-11-25 03:41
  • 4166

自顶向下深入分析Netty(八)--ChannelHandler

8.1 总述 由第七节的讲述可知ChannelHandler并不处理事件,而由其子类代为处理:ChannelInboundHandler拦截和处理入站事件,ChannelOutboundHandler拦截和处理出站事件。ChannelHandler和ChannelHandlerContext通...
  • yexin94822739
  • yexin94822739
  • 2017-06-16 17:08
  • 552

Netty4.0学习笔记系列之四:混合使用coder和handler

Handler如何使用在前面的例子中已经有了示范,那么同样是扩展自ChannelHandler的Encoder和Decoder,与Handler混合后又是如何使用的?本文将通过一个实际的小例子来展示它们的用法。 该例子模拟一个Server和Client,两者之间通过http协议进行通讯,在Serve...
  • u013252773
  • u013252773
  • 2014-03-19 23:53
  • 11235

Netty内部组件 in out bound handler等

读完这一章,我们基本上可以了解到Netty所有重要的组件,对Netty有一个全面的认识,这对下一步深入学习Netty是十分重要的,而学完这一章,我们其实已经可以用Netty解决一些常规的问题了。 一、先纵览一下Netty,看看Netty都有哪些组件? 为了更好的理解和进一步深入Netty,我们先...
  • z69183787
  • z69183787
  • 2016-09-20 11:21
  • 632

Netty中ChannelHandler共享数据的方式

(一)成员变量public class DataServerHandler extends SimpleChannelHandler { // 成员变量 private boolean loggedIn; @Override public void messageRec...
  • u013721793
  • u013721793
  • 2016-04-20 20:52
  • 3789
    个人资料
    • 访问:2217次
    • 积分:299
    • 等级:
    • 排名:千里之外
    • 原创:29篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类