TCP粘包/拆包问题之Netty解决方案

TCP以流的方式进行数据传输,上层的应用协议为了对消息进行区分,往往采用如下四种方式:消息长度固定,累计读取到长度总和为定长LEN的报文后,就认为读取到了一个完整的消息;将计数器置位,重新开始读取下一个数据报;将回车换行符作为消息结束符,例如FTP协议,这种方式在文本协议中应用比较广泛;将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的结束分隔符;通过在消息头中定义...
摘要由CSDN通过智能技术生成

TCP以流的方式进行数据传输,上层的应用协议为了对消息进行区分,往往采用如下四种方式:

  • 消息长度固定,累计读取到长度总和为定长LEN的报文后,就认为读取到了一个完整的消息;将计数器置位,重新开始读取下一个数据报;

  • 将回车换行符作为消息结束符,例如FTP协议,这种方式在文本协议中应用比较广泛;

  • 将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的结束分隔符;

  • 通过在消息头中定义长度字段来标识消息的总长度。
    Netty对上面四种应用做了统一的抽象,提供了四种解码器来解决对应的问题,使用起来非常方便。使用这些解码器,用户不需要自己对读取的报文进行人工解码,也不需要考虑TCP的粘包与拆包。
    Netty提供解码器如下:

  • DelimiterBasedFrameDecoder 基于消息边界方式进行粘包拆包处理

  • FixedLengthFrameDecoder 基于固定长度消息进行粘包拆包处理

  • LengthFieldBasedFrameDecoder 基于消息头指定消息长度进行粘包拆包处理

  • LineBasedFrameDecoder 基于行来进行消息粘包拆包处理

1.DelimiterBasedFrameDecoder原理:

DelimiterBasedFrameDecoder类属性

 /**
     * 分隔符
     */
    private final ByteBuf[] delimiters;
    /**
     * 最大帧长度
     */
    private final int maxFrameLength;
    /**
     * 是否跳过分隔符,就是最终解码的数据里面是否包含分隔符
     */
    private final boolean stripDelimiter;
    /**
     * 为true说明发现督导的数据已经超过maxFrameLength,立即报TooLongFrameException,
     * false-读完整个帧数据后再报
     */
    private final boolean failFast;
    /**
     * 当前的解码器是否处于discardingTooLongFrame状态,是一个标志位,在构造函数里不能进行设置,
     * 只能在解码器里进行设置
     */
    private boolean discardingTooLongFrame;
    /**
     * 是一个状态属性,就是说出现了超长帧了,哪这个帧的长度到底是多少,就是这个长度,
     * 一般来说是在发现当前buffer的可读数据超过最大帧时候进行设置
     */
    private int tooLongFrameLength;
    /** Set only when decoding with "\n" and "\r\n" as the delimiter.  */
    private final LineBasedFrameDecoder lineBasedDecoder;

主要构造函数,主要是在传递多个delimiter的时候进行slice操作,最终调用decode方法进行解码

public DelimiterBasedFrameDecoder(
            int maxFrameLength, boolean stripDelimiter, boolean failFast, ByteBuf... delimiters) {
   
        validateMaxFrameLength(maxFrameLength);
        if (delimiters == null) {
   
            throw new NullPointerException("delimiters");
        }
        if (delimiters.length == 0) {
   
            throw new IllegalArgumentException("empty delimiters");
        }

        if (isLineBased(delimiters) && !isSubclass()) {
   
            lineBasedDecoder = new LineBasedFrameDecoder(maxFrameLength, stripDelimiter, failFast);
            this.delimiters = null;
        } else {
   
            this.delimiters = new ByteBuf[delimiters.length];
            for (int i = 0; i < delimiters.length; i ++) {
   
                ByteBuf d = delimiters[i];
                validateDelimiter(d);
                this.delimiters[i] = d.slice(d.readerIndex(), d.readableBytes());
            }
            lineBasedDecoder = null;
        }
        this.maxFrameLength = maxFrameLength;
        this.stripDelimiter = stripDelimiter;
        this.failFast = failFast;
    }

DelimiterBasedFrameDecoder类的decode方法:

protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
   
        if (lineBasedDecoder != null) {
   
            return lineBasedDecoder.decode(ctx, buffer);
        }
        // Try all delimiters and choose the delimiter which yields the shortest frame.
        int minFrameLength = Integer
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值