netty channelpipeline 介绍

netty channelpipeline 介绍

先给出代码,代码解释在后面。

public class EchoServer1 {
    private final  int port;
    public EchoServer1(int port) {
        this.port = port;
    }

    public void start() throws Exception{
        EchoInServerHandler1 inServerHandler1 = new EchoInServerHandler1();
        EchoInServerHandler2 inServerHandler2 = new EchoInServerHandler2();
        EchoOutServerHandler1 outServerHandler1 = new EchoOutServerHandler1();
        EchoOutServerHandler2 outServerHandler2 = new EchoOutServerHandler2();

        EventLoopGroup group = new NioEventLoopGroup()
        try{
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel socketChannel) throws Exception {
                            System.out.println(socketChannel.pipeline().getClass().getName());
                            socketChannel.pipeline().addLast(inServerHandler1);
                            socketChannel.pipeline().addLast(outServerHandler1);
                            socketChannel.pipeline().addLast(inServerHandler2);
                            socketChannel.pipeline().addLast(outServerHandler2);
                        }
                    });
            ChannelFuture f = b.bind().sync();
            f.channel().closeFuture().sync();

        }finally {
            group.shutdownGracefully().sync();
            System.out.println("shutdownGracefully");
        }

    }

    @ChannelHandler.Sharable
    public class EchoInServerHandler1 extends ChannelInboundHandlerAdapter {

        @Override
        public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
            System.out.println("************************in1 执行************************");
            ByteBuf in = (ByteBuf) msg;
            System.out.println("in Server1 received: "+in.toString(CharsetUtil.UTF_8));
            //ctx.channel().writeAndFlush(Unpooled.wrappedBuffer((in.toString(CharsetUtil.UTF_8)+"-in server1-response").getBytes()));
    super.channelRead(ctx,Unpooled.wrappedBuffer(("test11111111111111111").getBytes()));
        }

    }

    @ChannelHandler.Sharable
    public class EchoInServerHandler2 extends ChannelInboundHandlerAdapter{

        @Override
        public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
            System.out.println("************************in2 执行************************");
            ByteBuf in = (ByteBuf) msg;
            System.out.println("in Server2 received: "+in.toString(CharsetUtil.UTF_8));
            super.channelRead(ctx,msg);
        }
    }

    @ChannelHandler.Sharable
    public class EchoOutServerHandler1 extends ChannelOutboundHandlerAdapter{

        @Override
        public void write(ChannelHandlerContext ctx , Object msg , ChannelPromise promise) throws Exception {
            System.out.println("************************out1 执行************************");
            ByteBuf byteMsg = (ByteBuf) msg;
            System.out.println("out1 received:"+byteMsg.toString(Charset.forName("utf8")));
            super.write(ctx,msg,promise);
        }
    }

    @ChannelHandler.Sharable
    public class EchoOutServerHandler2 extends ChannelOutboundHandlerAdapter{

        @Override
        public void write(ChannelHandlerContext ctx , Object msg , ChannelPromise promise) throws Exception {
            System.out.println("************************out2 执行************************");

            ByteBuf byteMsg = (ByteBuf) msg;
            System.out.println("out2 received:"+byteMsg.toString(Charset.forName("utf8")));
            super.write(ctx,msg,promise);
        }
    }

    public static void main(String[] args){
        try {
            int port = 3333;
            System.out.println("cccccccccccccccc");
            new EchoServer1(port).start();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

1.创建channel

创建两个in-channel和两个out-channel,如下图所示:

在这里插入图片描述

按照in1,out1,in2,out2的顺序加入到pipeline中。Pipeline在初始化时会自动加入两个默认的channelHandler,分别是in-out(在头部)和in(在尾部)。最终pipeline图如下所示:
绿色箭头是指向前一个out.
因为加入的顺序是in1,out1,in2,out2。所以:

  1. in1的前一个out是默认out,in1下一个in是in2;
  2. in2的前一个out是out1,in2下一个in是默认in;
  3. out1的前一个out是默认out,out1下一个in是in2;
  4. out2的前一个out是out1,out2下一个in是默认in;

这四点大家先记住,否则下面会混淆。

在这里插入图片描述
三个橙色的是pipeline默认加入的,源码如下:
会在pipeline头和尾默认加入。
1.其中head继承了in和out,所有头部有两个(一个in,一个out)。out会与网络连接,把数据写入网络。in会从网络接收数据,并把数据传给我们程序中定义的in1。
2.tail只继承了in,所有尾部只有一个in,这个in不会对消息作任何处理,只是抛弃消息。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.数据流向

in1从网络接收数据(通过头部默认的in),在的它的ChannelRead()方法中调用super.channelRead()方法把数据写入到pipeline中同一超类型的下一个in,就是in2。

在out2的write()方法中调用super.write(),会调用的是ctx.wriet(),所以会把数据写入out2的前一个out,就是out1,out1调用super.write(),把数据写入前一个out,就是默认的out。如果调用的是writeAndflush则会把数据写入网络。没有flush就不会写数据到网络.

In中调用write方法或writeAndFlush方法有两个方式

1. 调用channel的write或writeAndFlush方法,会执行尾端out的write方法。

源码如下,以调用writeAndFlush()来说明
channel的writeAndFlush会调用pipeline的writeAndFlush,
pipeline中会调用this.tail.writeAndFlush(),从尾端开始。
在这里插入图片描述
在这里插入图片描述
所以把in1中的channelRead()方法中的代码改成下图所示:
在这里插入图片描述

如上图所示,调用ctx.channel().writeAndFlush(),会导致从尾端out开始执行
此时执行顺序是in1,out2,out1,默认out,in2。

有两点要注意:

1.如果out1的write()方法中没有调用super.write(ctx,msg,promise);就不会执行默认的out,
此时执行顺序就是in1,out2,out1,in2。数据就不会写入到网络
2.如果out2的write()方法中没有调用super.write(ctx,msg,promise);就不会执行out1,也就不会执行默认out,此时执行顺序就是in1,in2,out2,数据就不会写入到网络。

因为代码super.channelRead()在ctx.channel().writeAndFlush()之后所在in2在out2之后执行,
如果super.channelRead()写在ctx.channel().writeAndFlush()前面,执行顺序就是in1,in2,out2,out1,默认out。

2. 调用ChannelHandlerContext的write或writeAndFlush方法,会执行当前的前一个out的writte()

源码如下,会找前一个out
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

把in1中的channelRead()方法中的代码改成下图所示:
在这里插入图片描述
如上图所示ctx.writeAndFlush(),会执行in1前一个out,就是默认的out,默认的out会直接把数据写回网络,注意如果调用的是ctx.write(),是不会写数据到网络的,只有flush才行。
此时执行顺序是in1,默认out,in2,
ctx.writeAndFlush()会写数据到网络。
如果把in2中的channelRead()方法中的代码改成下图所示:
在这里插入图片描述

如上图所示in2中ctx.writeAndFlush(),会执行in2之前的out的writeAndFlush(),就是out1,
此时执行顺序是in1,in2,out1,默认out。

总结下面两点,不管在in还是out中

1.要把数据传给下一个in,要调用ctx.fireChannelRead(msg)方法。
程序中可以这样写 super.channelRead(ctx, msg),本质上也是调用ctx.fireChannelRead(msg)方法。

2.要把数据传给out,调用channel或ctx的write方法。区别如下:

  1. 调用channel的write方法或writeAndFlush方法,会执行尾端的out的write方法。
    调用示例:ctx.channel().writeAndFlush(msg)

  2. 调用ChannelHandlerContext的write方法或writeAndFlush方法,会执行当前的前一个out的write方法。
    调用示例:ctx.writeAndFlush(msg)

从中可以得出:
1.如果尾端的out没有调用ctx.write(),就不会执行尾端out之前的out,数据就不会写入到网络
out要把数据写入前一个out必须调用ctx.write(),程序中可以这样写super.write(ctx, msg, promise),调用super的write本质上也是调用ctx.write()
2.in中调用ctx.write()会把数据传给它的前一个out的write()方法。
in 中调用ctx.channel().write()会把数据传给尾端的out的write()方法.

注意如果在out1中调用ctx.fireChannelRead(msg)方法,会把数据传给它的下一个in,就是in2,如果in2中又调用了ctx.write()方法,会把数据传给它的前一个out,就是out1.这样就会形成一个死循环。
如果在out1中调用ctx.channel().write()方法,会把数据传给尾部out,就是out2,如果out2中又调用了ctx.write()方法,会把数据传给它的前一个out,就是out1.这样也会形成一个死循环。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值