netty之bytebuf粘包、分包

之前开发一款上位机软件就被这个问题困扰的够呛,原因是因为当时我完全不知道还存在这样的问题,直到后来用了数据监控软件才发现了我那些参差不齐的数据包,又结合了之前在网上检索过的文章,最终才了解到了原来还有这么一回事。

所以,这次学netty的时候特意留了个心眼,提前搜索了一下netty是否也存在粘包这类问题,答案是存在!行吧,那就研究一下怎么解决吧。以下内容来自于笔者自学以及根据个人历史经验总结而成,暂时没在企业项目中处理过相关问题,不保证正确

首先,我自定义了一个非常简单的解码器,其实并不具备解码功能,目的就是为了证实我的一个猜测:

public class DecodeHandler extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        System.out.println(byteBuf.writerIndex());
    }
}

在解码器中,输出的是写索引的位置。

然后,我开始尝试触发解码器,发现当我不断向byteBuf中写入内容后,写索引也不断增长,我写入两字节,写索引就增大2,写入三字节,写索引就增加3。由此,我猜测每次接收数据准备进行解码的bytebuf都是同一个!而不是新建的bytebuf!

然后,就要根据实际情况来分析了,也就是要看数据的具体格式来分析。比如我之前遇到的那种返回值,是一个定长数组,没有固定的开头标识,除了依靠长度来解析我实在是想不出怎么解析。

但是,还有一种情况,数据是有开头标识的,比如每个数据包都以0x23,0x23来作为起始值。那么可以先找到数据的起始值在哪里。

private void find(ByteBuf buf) {
        int count = buf.readableBytes();
        for (int index = buf.readerIndex(); index < count - 2; index++) {
            if (buf.getByte(index) == 0x23 & buf.getByte(index + 1) == 0x23) {
                buf.readerIndex(index);
                return;
            }
        }
        buf.readerIndex(count - 1);
    }

比如可以这样找,或者也可以根据你的实际情况选择是否直接跳过开头标识。

然后,确定了读索引的位置就比较好办了,接下来的解析方式就看数据的具体格式了,在解析之前有必要检测一下数据长度是否完整,如果不完整,可以选择跳过这一波解析,等待数据接收完整再解析(记得要将读索引恢复到正确的位置)。

posted @ 2020-08-11 15:43  无心大魔王  阅读(804)  评论(0编辑  收藏  举报