美文网首页
netty中Channel,ChannelHandlerCont

netty中Channel,ChannelHandlerCont

作者: Ace_b90f | 来源:发表于2020-05-26 13:39 被阅读0次

Channel,ChannelHandler,ChannelPipeline,ChannelHandlerContext这些组件都有write,flush等方法,这些有什么区别呢

写一个测试项目,当前netty项目的出站方向有三个ChannelOutboundHandlerAdapter,添加pipeline时的方式如下

    socketChannel.pipeline()
                .addLast(new OutHandler2())
                .addLast(new OutHandler1())
                .addLast(new EchoClientChannelHandler())
                .addLast(new OutHandler3())
                ;

OutHandler1的代码如下所示

System.out.println(((ByteBuf)msg).toString(CharsetUtil.UTF_8));
System.out.println("~~~~~~~~~ out handler1 process ~~~~~~~");
ctx.writeAndFlush(Unpooled.copiedBuffer("handler1 change message", CharsetUtil.UTF_8));

OutHandler2,3的代码如下所示

System.out.println(((ByteBuf)msg).toString(CharsetUtil.UTF_8));
System.out.println("~~~~~~~~~ out handler3 process ~~~~~~~");
ctx.writeAndFlush(msg);

这时在EchoClientChannelHandler中使用ctx.channel().writeAnfFlush方法时,结果如下所示

Netty rocks!
~~~~~~~~~ out handler3 process ~~~~~~~
Netty rocks!
~~~~~~~~~ out handler1 process ~~~~~~~
handler1 change message
~~~~~~~~~ out handler2 process ~~~~~~~

若是改为在EchoClientChannelHandler中使用ctx.writeAndFlush方法,结构如下所示

Netty rocks!
~~~~~~~~~ out handler1 process ~~~~~~~
handler1 change message
~~~~~~~~~ out handler2 process ~~~~~~~

若是改为在EchoClientChannelHandler中使用ctx.channel().pipeline().writeAndFlush方法时,结果如下所示

Netty rocks!
~~~~~~~~~ out handler3 process ~~~~~~~
Netty rocks!
~~~~~~~~~ out handler1 process ~~~~~~~
handler1 change message
~~~~~~~~~ out handler2 process ~~~~~~~

若是EchoClientChannelHandler中直接调用某个ChannelHandler的write方法,如下所示

ctx.pipeline().get(OutHandler1.class)
                .write(ctx, Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8), new VoidChannelPromise(ctx.channel(),true));

结果如下所示

Netty rocks!
~~~~~~~~~ out handler1 process ~~~~~~~
handler1 change message
~~~~~~~~~ out handler1 process ~~~~~~~
handler1 change message
~~~~~~~~~ out handler2 process ~~~~~~~

若是改为在EchoClientChannelHandler中调用某个context的write方法,如下所示

ctx.pipeline().context(OutHandler1.class).writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));

结果如下所示

Netty rocks!
~~~~~~~~~ out handler2 process ~~~~~~~
EchoClient receives: Netty rocks!

基于上面的测试结果,联系netty in action 中讲的

如果调用Channel或者ChannelPipeline上的这些方法,他们将沿着整个ChannelPipeline进行传播。而调用位于ChannelHandlerContext上的相同方法,则将从当前所关联的ChannelHandler开始,并且只会传播给位于该ChannelPipeline中的下一个能够处理该事件的ChannelHandler。

这就可以解释上面使用channel,pipeline,ctx这些组件write时的输出结果了。

要想调用从某个特定的ChannelHandler开始的处理过程,必须获取到在该ChannelHandler之前的ChannelHandler所关联的ChannelHandlerContext。这个ChannelHandlerContext将调用和它所关联的ChannelHandler之后的ChannelHandler。

消息将从下一个ChannelHandler开始流经ChannelPipeline,绕过所有前面的ChannelHandler。

这就解释了上面在直接获取OutHandler1的context后,消息直接从OutHandler2开始处理。

但是直接调用ChannelHandler的结果还是不好解释。

将OutHandler1的write方法改为

ctx.pipeline().context(OutHandler2.class).writeAndFlush(Unpooled.copiedBuffer("handler1 change message", CharsetUtil.UTF_8));

结果变为

Netty rocks!
~~~~~~~~~ out handler1 process ~~~~~~~

可以看到直接调用ChannelHandler时类似直接的方法调用,相当于直接在当前的HandlerConext中执行调用的ChannelHandler方法,方向的流转取决于调用方。

  • 若调用的ChannelHandler中没有改变消息的流向,即直接ctx.write,那么就是普通的context间的消息流转。由于出站方向是注册Handler时的反方向,且OutHandler1注册在EchoClientChannelHandler前面,所以会产生了两次OutHandler1的调用。
  • 若调用的ChannelHandler中改变了消息的流向,即调用了channel或者pipeline或者其他context的write方法,那么消息就按照调用方的顺序来流转了。由于OutHandler2在注册时的头部,所以在修改OutHandler1的方法后消息直接走到了pipeline的末尾。

相关文章

网友评论

      本文标题:netty中Channel,ChannelHandlerCont

      本文链接:https://www.haomeiwen.com/subject/bagmahtx.html