netty入门-6 Handler和Pipeline

前言

书上讲服务器客户端创建三个要点,线程模型(Group),IO模型(NioSocketChannel),处理逻辑。
这篇的HandlerPipeline,就是我们IO操作的处理逻辑。
然后下篇说ByteBuf这个Netty自己实现的数据封装组件。

Handler和Pipeline

我们主要谈论ChannelHandlerChannelPipeline
前文也说过这俩东西,Pipeline就是多个Handler构成的。
数据经过多个Handler处理,不就是一个流水线加工的形式吗。
下面来具体说说。

首先,一个连接对应一个Channel,这是前面说到过的。每个连接经过ServerSocketChannel处理连接请求,生成一个与之对应的SocketChannel
而每个Channel同样也对应一个Pipeline。而一个Pipeline可能里面有多个Handler了。Pipeline内部的Handler是双向链表形式连接。

ChannelHandler接口有两个子接口,ChannelInboundHandler(实现类 ChannelInboundHandlerAdapter)和ChannelOutboundHandler(实现类 ChannelOutboundHandlerAdapter)。
顾名思义,Inbound自然是读数据时的处理,而Outbound是写数据时的处理。
Inbound的方法是channelRead(),对应channel读取数据时做的处理。
Outbound的方法是write(),对应向channel写数据之前做什么处理。

所以ChannelInboundHandlerAdapter内重写的channelRead()会在读取Channel数据时触发。
ChannelOutboundHandlerAdapter内重写的write()在写操作时触发。

Handler构成的双向链表就可以看做Pipeline
那么这个双向链表是什么样的呢?
先看示例代码添加的Handler

new ServerBootstrap()
    .group(new NioEventLoopGroup())
    .channel(NioServerSocketChannel.class)
    .childHandler(new ChannelInitializer<NioSocketChannel>() {
        protected void initChannel(NioSocketChannel ch) {
            ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                @Override
                public void channelRead(ChannelHandlerContext ctx, Object msg) {
                    System.out.println(1);
                    ctx.fireChannelRead(msg); // 1
                }
            });
            ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                @Override
                public void channelRead(ChannelHandlerContext ctx, Object msg) {
                    System.out.println(2);
                    ctx.fireChannelRead(msg); // 2
                }
            });
            ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                @Override
                public void channelRead(ChannelHandlerContext ctx, Object msg) {
                    System.out.println(3);
                    ctx.channel().write(msg); // 3
                }
            });
            ch.pipeline().addLast(new ChannelOutboundHandlerAdapter(){
                @Override
                public void write(ChannelHandlerContext ctx, Object msg, 
                                  ChannelPromise promise) {
                    System.out.println(4);
                    ctx.write(msg, promise); // 4
                }
            });
            ch.pipeline().addLast(new ChannelOutboundHandlerAdapter(){
                @Override
                public void write(ChannelHandlerContext ctx, Object msg, 
                                  ChannelPromise promise) {
                    System.out.println(5);
                    ctx.write(msg, promise); // 5
                }
            });
            ch.pipeline().addLast(new ChannelOutboundHandlerAdapter(){
                @Override
                public void write(ChannelHandlerContext ctx, Object msg, 
                                  ChannelPromise promise) {
                    System.out.println(6);
                    ctx.write(msg, promise); // 6
                }
            });
        }
    })
    .bind(8080);

上述代码最后形成的双向链表是这样的。
在这里插入图片描述

这不就是按add的顺序插进链表吗。确实是,但是执行操作的顺序是有变化的。
我们的读事件,会按链表中的Inbound的顺序从前向后传递。每个Handler执行自己的逻辑然后把事件传给下一个InboundHandler。当然,不会传给OutboundHandler。按图来说就是In_1,In_2,In_3的顺序
而对于写事件在OutboundHandler中的传播顺序则与添加顺序相反,是从链表尾部最后addOutboundHandler开始向前传到第一个OutboundHandler。按图,执行顺序为,Out_6,Out_5,Out_4
inboundHandler的执行顺序与实际的添加顺序相同,而outboundHandler则相反。

结语

本文仅涉及到Handler处理的触发顺序。对于我们使用时一般在Handler里做什么没有介绍。一般来说就是做数据的编码解码,或者打印一些信息。

总结一下,每个Channel有自己的Pipeline,内部的Handler有我们进行配置。
其中读会走InboundHandler处理。写会走OutBoundHandler处理。
还有就是执行顺序,InboundHandler的执行顺序与添加顺序相同。OutBoundHandler则是相反。

下篇就是数据载体ByteBuf了。
然后基本组件就说完了。Netty的基本使用也就是这些组件的使用。
剩下的就是一些组件深层次的原理与现象了(比如主从Reactor模型,组件的源码实现),这部分可能不影响使用,但对于理解Netty很有帮助。

我觉得仅仅了解这些东西的基本使用,我们还是很难用它去做一个什么聊天室,RPC之类的东西。
所以还是需要学习别人怎么做的,做这个的框架,要有什么样的功能怎么实现,会出现什么问题怎么解决。

感谢阅读,欢迎批评指正。

  • 14
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值