美文网首页
Netty笔记-ByteToMessageDecoder拆包问题

Netty笔记-ByteToMessageDecoder拆包问题

作者: 兴浩 | 来源:发表于2018-07-25 15:45 被阅读95次

    netty笔记-Codec编码与解码

    1.触发场景

    Client端发出Netty rocks!字符串,Server将其解释成3个Integer类型

        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            // 当被通知Channel是活跃的时候,发送一条消息
            ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
        }
    

    Decode

    public class ToIntegerDecoder extends ByteToMessageDecoder {
        @Override
        public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
            if(in.readableBytes()>0)
            {
                out.add(String.valueOf(in.readInt()));
            }
        }
    }
    

    结果是Server同时接收到3次请求处理,直接将发出请求截断掉了

    Server received: 1315271796
    Server received: 2032169583
    Server received: 1667986209
    

    2. ByteToMessageDecoder的callDecode方法

        protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
            try {
                while (in.isReadable()) {
                    int outSize = out.size();
    
                    if (outSize > 0) {
                        fireChannelRead(ctx, out, outSize);
                        out.clear();
    
                        // Check if this handler was removed before continuing with decoding.
                        // If it was removed, it is not safe to continue to operate on the buffer.
                        //
                        // See:
                        // - https://github.com/netty/netty/issues/4635
                        if (ctx.isRemoved()) {
                            break;
                        }
                        outSize = 0;
                    }
    
                    int oldInputLength = in.readableBytes();
                    decodeRemovalReentryProtection(ctx, in, out);
    
                    // Check if this handler was removed before continuing the loop.
                    // If it was removed, it is not safe to continue to operate on the buffer.
                    //
                    // See https://github.com/netty/netty/issues/1664
                    if (ctx.isRemoved()) {
                        break;
                    }
    
                    if (outSize == out.size()) {
                        if (oldInputLength == in.readableBytes()) {
                            break;
                        } else {
                            continue;
                        }
                    }
    
                    if (oldInputLength == in.readableBytes()) {
                        throw new DecoderException(
                                StringUtil.simpleClassName(getClass()) +
                                        ".decode() did not read anything but decoded a message.");
                    }
    
                    if (isSingleDecode()) {
                        break;
                    }
                }
            } catch (DecoderException e) {
                throw e;
            } catch (Throwable cause) {
                throw new DecoderException(cause);
            }
        }
    
        final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
                throws Exception {
            decodeState = STATE_CALLING_CHILD_DECODE;
            try {
                decode(ctx, in, out);
            } finally {
                boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING;
                decodeState = STATE_INIT;
                if (removePending) {
                    handlerRemoved(ctx);
                }
            }
        }
    
    • 其主要是循环调用decode方法,循环的条件是还有数据可读
    • 子类更新List<Object>数据,每次读到数据则发起一次ChannelRead事件(fireChannelRead)

    根据以上代码,如果不想调用多次ChannelRead事件,则需要在解码的时候,一次将数据解码完成,如下示例

    public class ToIntegerDecoder extends ByteToMessageDecoder {
        @Override
        public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
            StringBuilder sb=new StringBuilder();
            // 检查是否至少有4字节可读(一个int的字节长度)
            while (in.readableBytes() >= 4) {
                sb.append(String.valueOf(in.readInt()));
            }
            out.add(sb.toString());
        }
    }
    

    输出结果

    Server received: 131527179620321695831667986209
    

    相关文章

      网友评论

          本文标题:Netty笔记-ByteToMessageDecoder拆包问题

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