一起学netty(11)handler 和 pipeline 概念的理解

weblog 1441 0 0

ChannelHandler用来处理Channel上的各种事件(包括建立连接,数据收发,异常处理等)

ChannelHandler分为出站和入栈两种。所有的ChannelHandler被连接成一串,就是一个Pipeline

入栈处理器通常是ChannelInboundHandlerAdapter的子类,主要用于读取和处理客户端的数据。(包括数据包解码,业务逻辑处理等)

出栈处理器通常是ChannelOutboundHandlerAdapter的子类,主要用于向客户端回写数据的处理。(包括回写数据的编码等)

打个比喻,每个Channel是一个产品的加工车间,Pipeline是车间中的流水线,ChannelHandler就是流水线上的各道工序,ByteBuf是原材料,经过很多工序的加工︰先经过一道道入站工序,再经过一道道出站工序最终变成产品。

SocketChannel实例中可以获取到ChannelPipeline的实例。调用ChannelPipeline.addLast方法可以将一个事件处理器添加到处理器链的末尾,当然也有其他的方法可以添加到头部,或某个handler的后面等。注意,netty会默认在Pipeline的头部和尾部加一个默认的handler。自定义添加的handler都会在head和tail内部。

程序案例:

public class NettyServer2 {
    public static void main(String[] args) throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG,1024)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        //添加一个handler(入栈处理器)
                        pipeline.addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                System.out.println("first handler:" + msg.getClass().getName());
                                Integer data = new Integer(1);
                                //将数据传给下一个handler处理,如果不执行fireChannelRead方法,下一个handler将不会执行
                                ctx.fireChannelRead(data);
                            }
                        });
                        //添加一个handler(入栈处理器)
                        pipeline.addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                System.out.println("second handler:" + msg.getClass().getName()+" -> "+msg);
                                String data = "this is data";
                                //将数据传给下一个handler处理,如果不执行fireChannelRead方法,下一个handler将不会执行
                                ctx.fireChannelRead(data);
                            }
                        });
                        //添加一个handler(!!!出栈处理器)
                        /**
                         * 当向客户端回写数据的时候会触发
                         */
                        pipeline.addLast(new ChannelOutboundHandlerAdapter(){
                            @Override
                            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                                System.out.println("third handler:"+msg);
                                ctx.fireChannelActive();
                            }
                        });
                        //添加一个handler(入栈处理器)
                        pipeline.addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                System.out.println("fourth handler:" + msg.getClass().getName()+" -> "+msg);
                                //向客户端回写数据
                                ctx.writeAndFlush("你好");
                            }
                        });
                    }
                });
        ChannelFuture channelFuture = serverBootstrap.bind(8077).sync();
        channelFuture.channel().closeFuture().sync();
    }
}

以上程序Pipeline执行的过程是:head -> first handler -> second handler -> fourth handler -> third handler -> tail

当有数据发送的时候会打印如下结果:

为什么fourth handler会在 third handler 前执行,因为third handler是一个出栈处理器,服务器接收到数据后会先执行完入栈处理器,当服务器向客户端回写数据的时候才会执行出栈处理器,所以当fourth handler执行writeAndFlush方法后向客户端发送消息“你好”,此时才会执行third handler做一些数据的处理等操作。

看到这里相信你对handler和pipeline已经有了一个大概的认识,后面将要介绍的编码和解码的问题,以及自定义协议的问题,都和ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter有着直接的联系。所以对handler和pipeline的理解至关重要。


猜你喜欢
mqtt协议 1589 应用程序消息;(4)断开与服务器连接。mqtt服务器MQTT服务器以称为”消息代”(Broker),可以是个应用程序或台设备。它是位于消息发布者订阅者之间,它可以:(1)接受来自客户网络连
official 1480 编码器码器在网络应用中需要实现某种编码器,将原始字节数据与自定义消息对象进行互相转换。网络中都是以字节码数据形式来传输数据,服务器编码数据后发送到客户端,客户端需要对数据进行
official 1379 之前文章中提到了java中nio是同步非阻塞网络io模型,本文就主要说明下同步、异步、阻塞、非阻塞来帮助nio。io操作IO分两阶段(旦拿到数据后就变成了数据操作,不再是IO
official 1205 什么是心跳?顾名思义,所谓心跳,即在TCP长连接中,客户端服务器之间定期发送种特殊数据包,通知对方自己还在线,以确保TCP连接有效性。为什么需要心跳?因为网络不可靠性,有可能在TCP保持
official 1453 之前文章中提到过,单线程nio模型任然有定缺点。在上节《netty(7)netty线程模型》中也提到,netty出现,封装了nio复杂代码,并且介入多线程来处事件,最大限度
official 1114 调度基本当有堆任务要处,但由于资源有限,这些事情没法同时处。这就需要确定某种规则来决定处这些任务顺序,这就是“调度”研究问题。在多道程序系统中,进程数量往往是多于处个数
official 1932 篇《netty(2)nio模型及多路复用器》中已经简单介绍了nio模型,以及多路复用器,并了nio是非阻塞网络模型,以及与bio区别。本篇将继续深入nio,以及select
official 1295 netty包下ServerSocketChannel或SocketChannelnio包下ServerSocketChannel或SocketChannel。只不过netty中又重新对nio
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。