zoukankan      html  css  js  c++  java
  • netty之handler write

    转载自:https://blog.csdn.net/FishSeeker/article/details/78447684

    实验过,例如channle的handler里有很多个outhandler,在out里面写writeAndFlush要使用ctx.writeAndFlush,

    因为channle.WriteAndFlush是这样执行的out1->out2->out3->out4

    假设在out3的时候使用channel.Write,那么这个处理又从out1开始,陷入死循环

    Netty中ctx.writeAndFlush与ctx.channel().writeAndFlush的区别

    最近在写netty相关代码,发现writeAndFlush这个方法既可以在ctx上调用,也可以在channel上调用,这两者有什么区别呢,于是就做了一个小实验。具体的代码在最后

    Client端
    client的handler
    这次我们主要在服务端进行实验,因此client端就简单构造一个handler用来接收发来的信息并传送回去,以形成和server通信的态势。

    public class C_I_1 extends ChannelInboundHandlerAdapter{
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    Number n = (Number)msg;
    System.out.println("C in 111 get num = " + n.getNum());
    n.add();
    ctx.writeAndFlush(n);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    这里构建了一个Number实体类,就是存一个数而已。add方法就是让类的数加一。client的handler就是这个了。

    client构建
    这就是日常的netty客户端的构建方法,具体的怎么绑定什么的不讲了。然后我们在连接服务端之后向服务端发出一个数字1

    public class Client {
    static String host = "127.0.0.1";
    static int port = 10010;
    public static void main(String[] args) {
    EventLoopGroup group = new NioEventLoopGroup();
    Bootstrap b = new Bootstrap();
    b.group(group)
    .channel(NioSocketChannel.class)
    .option(ChannelOption.TCP_NODELAY,true)
    .handler(new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
    //这里一定要加入这两个类,是用来给object编解码的,如果没有就无法传送对象
    //并且,实体类要实现Serializable接口,否则也无法传输
    ch.pipeline().addLast(new ObjectEncoder());
    ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE,
    ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度
    ch.pipeline().addLast(new C_I_1());
    }
    });
    try {
    Number n = new Number();
    n.setNum(1);
    ChannelFuture f =b.connect(host,port).sync();
    f.channel().writeAndFlush(n);
    f.channel().closeFuture().sync();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }finally {
    group.shutdownGracefully();
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    Server端
    Server的handler就稍微多一点,为了验证ctx和channel的writeAndFlush到底有什么不同,我们决定建立四个Handler,两个out,两个In,然后交换它们的顺序来看效果。

    handler
    这里的handler就是接受一个Number类,然后让这个数加一再进行下一步操作。

    inboundhandler
    public class S_I_1 extends ChannelInboundHandlerAdapter{
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    Number n = (Number)msg;
    System.out.println("S in 111 get num = " + n.getNum());
    n.add();
    ctx.fireChannelRead(n);
    //ctx.channel().writeAndFlush(n);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    outboundhandler
    public class S_O_1 extends ChannelOutboundHandlerAdapter {

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    Number n = (Number)msg;
    System.out.println("S out 111 get num = " + n.getNum());
    n.add();
    ctx.writeAndFlush(n);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    服务器构建
    public class Server {
    public static void main(String[] args) {
    EventLoopGroup bossGroup = new NioEventLoopGroup(),workerGroup = new NioEventLoopGroup();
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup,workerGroup)
    .channel(NioServerSocketChannel.class)
    .option(ChannelOption.SO_BACKLOG,1024)
    .childOption(ChannelOption.SO_KEEPALIVE,true)
    .childHandler(new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
    //这个object转换的如果不放在前面会在发送的时候找不到out
    ch.pipeline().addLast(new ObjectEncoder());
    ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE,
    ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度
    ch.pipeline().addLast(new S_I_1());
    ch.pipeline().addLast(new S_O_1());
    ch.pipeline().addLast(new S_I_2());
    ch.pipeline().addLast(new S_O_2());
    }
    });
    try {
    ChannelFuture f = b.bind(10010).sync();
    f.channel().closeFuture().sync();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }finally {
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    实验
    先说实验结论就是ctx的writeAndFlush是从当前handler直接发出这个消息,而channel的writeAndFlush是从整个pipline最后一个outhandler发出。怎么样,是不是很抽象,下面画图来看一看:

    啊,首先解释一下这个图,黑色的是inhandler,红色的是outhandler,前面圆形的是编解码器,必须放在pipline的最前头,否则会让信息发不出去。然后,连接建立之后,in接收到一个数1,选择ctx的writeAndFlush,那么这个数,就会直接从圆形的out出去,因为我们的结论说了,就是从当前的handler直接发出去这个消息。如果使用ctx.channel().writeAndFlush()呢,就会让这个数从红色的2开始发送,经过红色1,再发出去。

    让我们看一看另一种情况:

    这种情况下,我们让黑色1接收到信息之后fire到黑色2,然后让黑色2把信息writeAndFlush出去,如果使用ctx.writeAndFlush(),那么这个信息就会经过红色1而不经过红色2,如果使用ctx.channel().writeAndFlush()就会从pipline的尾部,也就是红色2开始,经过红色1发出去。

    下午写代码的时候突然想到了这种情况,就是在红色的2里,如果用channel的writeAndFlush会有什么样的结果。实验之后发现,是一个死循环,2通过channel的writeAndFlush把消息送回pipline尾部,然后自己获得这个消息,再送回尾部,这样永远都发不出了,这一定要注意哦

    好的,就是这样了。
    ---------------------
    作者:FishSeeker
    来源:CSDN
    原文:https://blog.csdn.net/FishSeeker/article/details/78447684
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    Android性能优化典范
    通过命令行连接oracle数据库/进入sql plus
    eclispe 出现超内存错误
    eclipse 重装了tomcat后配置路径
    dorado listener属性
    dorado问题查询&快捷键重命名
    dorado spring知识补充
    Eclipse导入包的快捷键
    dorado抽取js
    dorado中的creationType选择类型
  • 原文地址:https://www.cnblogs.com/heroinss/p/10243425.html
Copyright © 2011-2022 走看看