netty(四)pipline 顺序实践

1. inbound 和 outbound 

理论上,InboundHandler顺序执行,OutboundHandler逆序执行,实际上有坑:

                    //定长解码类
                    pipeline.addLast(new FixedLengthFrameDecoder(14));
                    //字符串解码类
                    pipeline.addLast(new StringDecoder());
                    //处理类 inbound
                    pipeline.addLast(new ServerHandler4());
                    pipeline.addLast(new StringEncoder());
                                    

 

其中,FixedLengthFrameDecoder为,StringDecoder,ServerHandler4为inboundHandler 

ServerHandler4接收客户端的字符串,然后返回客户端的字符串

但失败了,表现为服务器能接收,但客户端没有接收到服务器返回的字符串,修改为:  

                    //定长解码类
                    pipeline.addLast(new FixedLengthFrameDecoder(14));
                    //字符串解码类
                    pipeline.addLast(new StringDecoder());
                    pipeline.addLast(new StringEncoder());
                    //处理类
                    pipeline.addLast(new ServerHandler4());

  

这样就可以,分析:

ServerHandler4中的writeAndFlush,会逆序调用OutboundHandler,但不是从pipeline末尾,而是从ServerHandler4往上搜索,结果没找到StringEncoder和其它outBoundHandler,无法完成编码:https://blog.csdn.net/wgyvip/article/details/25637651

 

还有种方法:ctx.writeAndFlush 改为 ctx.channel().writeAndFlush,channel的write会从pipeline头开始搜索

 

此外,FixedLengthFrameDecoder需要在StringDecoder之前

 

 

2.read函数的传递性

如果不改写ChannelInboundHandlerAdapter的channelRead,则channelRead会调用pipeline中下一个ChannelInboundHandlerAdapter的channelRead:

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.fireChannelRead(msg);
}

所以如果改写了channelRead,则意味着链路其后的ChannelInboundHandlerAdapter不会收到channelRead,除非显式调用fire~:

                    //获取管道
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    //定长解码类
                    pipeline.addLast(new FixedLengthFrameDecoder(14));
                    //字符串解码类
                    pipeline.addLast(new StringDecoder());

                    pipeline.addLast(new StringEncoder());
                    //处理类
                    pipeline.addLast(new ServerHandler4());
                    pipeline.addLast(new ServerHandler5());

  

class ServerHandler4 extends SimpleChannelInboundHandler<String> {

    //用于记录次数
    private int count = 0;
    //读取客户端发送的数据
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("RESPONSE--------"+msg+";"+"   @ "+ ++count);

        /**
         * channel的write会从pipeline头上查找outbound
         */
        // ctx.channel().writeAndFlush(msg);

        // 注意复制
        StringBuilder stringBuilder = new StringBuilder().append(msg);
        String newMsg = stringBuilder.toString();
        ctx.writeAndFlush(newMsg);

        // 显式转发
        ctx.fireChannelRead("转发:"+ newMsg);
    }

  

最后的fireChannelRead是必须的,覆盖channelRead函数后,消息不再往下传递,需要手动传递

class ServerHandler5 extends SimpleChannelInboundHandler<String> {

    //用于记录次数
    private int count = 0;
    //读取客户端发送的数据
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("RESPONSE5--------"+msg+";"+"   @ "+ ++count);

  

输出:

RESPONSE--------I am client,--; @ 1
RESPONSE5--------转发:I am client,--; @ 1
RESPONSE--------I am client,--; @ 2
RESPONSE5--------转发:I am client,--; @ 2
RESPONSE--------I am client,--; @ 3
RESPONSE5--------转发:I am client,--; @ 3
RESPONSE--------I am client,--; @ 4
RESPONSE5--------转发:I am client,--; @ 4
RESPONSE--------I am client,--; @ 5
RESPONSE5--------转发:I am client,--; @ 5

 

注意:

1.因为使用SimpleChannelInboundHandler,转发时要复制msg,或retan byte增加引用寿命

2.如果存在多个handler都要处理msg,可使用ChannelInboundHandlerAdapter,这样可以避免频繁复制,注意手段fire传递,且最后一个adapter要释放msg

 

8.29  

1
2
3
4
5
6
7
8
class ServerHandler4 extends SimpleChannelInboundHandler<ByteBuf> { // ByteBuf 会跳过此handler
 
    //用于记录次数
    private int count = 0;
    //读取客户端发送的数据
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("RESPONSE--------"+msg+";"+"   @ "+ ++count);

  

handler4修改为ByteBuf,则会跳过此handler,直接到handler5,输出:

 

9.18

Handler4中不用复制(红色标注),因为String不是netty对象,不会被回收

posted on 2018-08-20 11:24  silyvin  阅读(501)  评论(0)    收藏  举报