LineBasedFrameDecoder resuelve el análisis del código fuente del paquete pegajoso y el medio paquete

Problema de bolsa pegajosa con media bolsa

1. El paquete de datos de bytes transmitido por la capa TCP no tiene significado y no está claro qué bytes de escritura deben ensamblarse.

2. En nuestro programa, generalmente es necesario deserializar una parte de la matriz de bytes como un paquete completo, si hay más

Los bytes o un byte menos no se deserializarán.

3. Podemos hacer una marca, como un carácter de nueva línea como una unidad de secuencia inversa, luego podemos sacarnos normalmente

El paquete de datos requerido, el procesador de LineBasedFrameDecoder es este principio, el método de uso es muy simple, siempre que

Después de enviar una matriz de bytes deserializada, agregue una nueva línea después de ella

LineBasedFrameDecoder resuelve el diagrama principal del paquete pegajoso

Inserte la descripción de la imagen aquí

LineBasedFrameDecoder resuelve el código fuente del paquete de la mitad del paquete pegajoso

//LineBasedFrameDecoder逻辑是根据换行符来进行拆包的,认为一个换行符前是一个完整包
//ByteToMessageDecoder的channelRead方法
//LineBasedFrameDecoder继承了ByteToMessageDecoder
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    
    
    if (msg instanceof ByteBuf) {
    
    
        CodecOutputList out = CodecOutputList.newInstance();
        try {
    
    
            ByteBuf data = (ByteBuf) msg;
            first = cumulation == null;
            if (first) {
    
    
                cumulation = data;
            } else {
    
    
                cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);
            }
            //1.对上个拦截器过来的数据进行拆包
            //2.查找到一个换行符,那么是认为是一个完整的字节包,那么添加到out中
            callDecode(ctx, cumulation, out);
        } catch (DecoderException e) {
    
    
            throw e;
        } catch (Throwable t) {
    
    
            throw new DecoderException(t);
        } finally {
    
    
            int size = out.size();
            decodeWasNull = !out.insertSinceRecycled();
            //将out中完整的包,交给下一个拦截器
            //如果只是半包,那么out里面是空,不会触发下一个处理器
            fireChannelRead(ctx, out, size);
            out.recycle();
        }
    } else {
    
    
        ctx.fireChannelRead(msg);
    }
}

//ByteToMessageDecoder的callDecode方法
//主要作用是以换行符切割性读取Buff里的数据,所以如果有粘包,那么会读取多次
 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();
                    if (ctx.isRemoved()) {
    
    
                        break;
                    }
                    outSize = 0;
                }

                int oldInputLength = in.readableBytes();
                //读取到换行符就会停止读取,进度下一轮
                decodeRemovalReentryProtection(ctx, in, out);
                
              //省去.....
            }
        } catch (DecoderException e) {
    
    
            throw e;
        } catch (Throwable cause) {
    
    
            throw new DecoderException(cause);
        }
    }

//ByteToMessageDecoder的fireChannelRead方法
//将一个分解的完整包,交给下一个处理器处理
static void fireChannelRead(ChannelHandlerContext ctx, CodecOutputList msgs, int numElements) {
    
    
        for (int i = 0; i < numElements; i ++) {
    
    
            ctx.fireChannelRead(msgs.getUnsafe(i));
        }
    }
//decodeRemovalReentryProtection方法内部调用
//LineBasedFrameDecoder的decode方法,自己实现拆包,根据自己换行符分割特性
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
    
    
        //查找换行符的字节位置
  			final int eol = findEndOfLine(buffer);
        if (!discarding) {
    
    
            if (eol >= 0) {
    
    
                final ByteBuf frame;
                final int length = eol - buffer.readerIndex();
                final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
								//一个完整包不能超过一个自己设置的一个长度,否则抛异常
                if (length > maxLength) {
    
    
                    buffer.readerIndex(eol + delimLength);
                    fail(ctx, length);
                    return null;
                }
								//将一个完整包拆分出一帧,然后停止读取
                if (stripDelimiter) {
    
    
                    frame = buffer.readRetainedSlice(length);
                    buffer.skipBytes(delimLength);
                } else {
    
    
                    frame = buffer.readRetainedSlice(length + delimLength);
                }

                return frame;
            } else {
    
    
                final int length = buffer.readableBytes();
                if (length > maxLength) {
    
    
                    discardedBytes = length;
                    buffer.readerIndex(buffer.writerIndex());
                    discarding = true;
                    offset = 0;
                    if (failFast) {
    
    
                        fail(ctx, "over " + discardedBytes);
                    }
                }
                return null;
            }
        } 
    }

Supongo que te gusta

Origin blog.csdn.net/weixin_38312719/article/details/108763753
Recomendado
Clasificación