Netty自定义数据包协议

粘包和分包出现的原因是:没有一个稳定数据结构

解决办法: 分割符

     长度 + 数据

 

* <pre>  
* 数据包格式
* +——----——+——-----——+——----——+——----——+——-----——+
* | 包头 | 模块号 | 命令号 | 长度 | 数据 |
* +——----——+——-----——+——----——+——----——+——-----——+
* </pre>
* 包头4字节
* 模块号2字节short
* 命令号2字节short
* 长度4字节(描述数据部分字节长度)

 

创建encoder  和 decoder  分别 加入pipeline 中

public class RpcDecoder extends ByteToMessageDecoder {

    private Class<?> genericClass;

    public RpcDecoder(Class<?> genericClass) {
        this.genericClass = genericClass;
    }

    @Override
    public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in.readableBytes() < 4) {
            return;
        }
        in.markReaderIndex();
        int dataLength = in.readInt();
        if (dataLength < 0) {
            ctx.close();
        }
        if (in.readableBytes() < dataLength) {
            in.resetReaderIndex();
            return;
        }
        byte[] data = new byte[dataLength];  
        in.readBytes(data);

        Object obj = SerializationUtil.deserialize(data, genericClass);
        out.add(obj);
    }
}
public class RpcEncoder extends MessageToByteEncoder {

    private Class<?> genericClass;

    public RpcEncoder(Class<?> genericClass) {
        this.genericClass = genericClass;
    }

    @Override
    public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {
        if (genericClass.isInstance(in)) {
            byte[] data = SerializationUtil.serialize(in);
            out.writeInt(data.length);
            out.writeBytes(data);
        }
    }
}
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in.readableBytes() >= BASE_LENGTH) {
            
            //防止socket字节流攻击
            if (in.readableBytes() > 2048) {
                in.skipBytes(in.readableBytes());
            }
            
            //记录包头开始的index
            int beginReader;
            
            //读取包头
            while (true) {
                beginReader = in.readerIndex();
                in.markReaderIndex();
                if (in.readInt() == Constantvalue.FLAG) {
                    break;
                }
                
                //未读到包头, 略过一个字节
                in.resetReaderIndex();
                in.readByte();
                
                //长度又变得不满足
                if (in.readableBytes() < BASE_LENGTH) {
                    return;
                }
            }
        }
        
        
            
            // 模块号
            short module  = in.readShort();
            //命令好
            short cmd = in.readShort();
            // 长度
            int dataLength = in.readInt();
            
            if (in.readableBytes() < dataLength) {
                 //还原读指针
                   in.resetReaderIndex();
                   return;
            }
            byte[] data = new byte[dataLength];
            in.readBytes(data);
            Request request = new Request();
            request.setModule(module);
            request.setCmd(cmd);
            request.setData(data);
            //继续往下传递
            out.add(request);
        
    }

 

buffer里面数据未被读取完怎么办

protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        try {
            while (in.isReadable()) {
                int outSize = out.size();
                int oldInputLength = in.readableBytes();
                decode(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;
                }
            }

数据缓存在 cumulation中

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ByteBuf) {
            RecyclableArrayList out = RecyclableArrayList.newInstance();
            try {
                ByteBuf data = (ByteBuf) msg;
                first = cumulation == null;    //第一次请求  cumulation 为 null    true  
                if (first) {
                    cumulation = data;
                } else {
                    cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data); // 第二次请求时进入 将新的信息追加到cumulation后面
                }
                callDecode(ctx, cumulation, out);
            } catch (DecoderException e) {
                throw e;
            } catch (Throwable t) {
                throw new DecoderException(t);
            } finally {
                if (cumulation != null && !cumulation.isReadable()) {
                    cumulation.release();
                    cumulation = null;
                }
                int size = out.size();

                for (int i = 0; i < size; i ++) {
                    ctx.fireChannelRead(out.get(i));
                }
                out.recycle();
            }
        } else {
            ctx.fireChannelRead(msg);
        }
    }

 

posted @ 2018-08-21 16:53  jojoworld  阅读(2273)  评论(0编辑  收藏  举报