Java:网络通信Netty接收包示例

Java:网络通信Netty接收包示例

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;
import java.util.List;

@Slf4j
public class NettyDecoder extends ByteToMessageDecoder {
    /**
     * 最短长度:包头 + 数据包长度 + 协议版本 + 命令码 + 包尾
     */
    private static final int MIN_LENGTH = 20;

    /**
     * 最大长度为10M
     */
    private static final long MAX_LENGTH = 1024 * 1024 * 10;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buffer,List<Object> out) throws Exception {
        // 记录包头开始的index
        int beginReader;
        while (true) {
            // 包长度大于最短长度
            if (buffer.readableBytes() >= MIN_LENGTH) {
                // 防止socket字节流攻击,客户端传来的数据过大
                if (buffer.readableBytes() > MAX_LENGTH) {
                    // 黏包分包处理
                    buffer.skipBytes(buffer.readableBytes());
                }
                while (true) {
                    // 获取包头开始的index
                    beginReader = buffer.readerIndex();
                    // 标记包头开始的index
                    buffer.markReaderIndex();
                    // 读到了协议的开始标志,结束while循环
                    if (buffer.readInt() == NettyDecoder.HEAD_DATA) {
                        log.debug("找到包头");
                        break;
                    }
                    // 未读到包头,略过一个字节
                    // 每次略过,一个字节,去读取,包头信息的开始标记
                    buffer.resetReaderIndex();
                    buffer.readByte();
                    // 当略过,一个字节之后,
                    // 数据包的长度,又变得不满足
                    // 此时,应该结束。等待后面的数据到达
                    if (buffer.readableBytes() < MIN_LENGTH) {
                        return;
                    }
                }
                // 消息的长度
                int length = buffer.readInt();
                // 超过最大长度
                if (length > MAX_LENGTH) {
                    buffer.readerIndex(beginReader + 1);
                    continue;
                }
                // 判断请求数据包数据是否到齐
                if (buffer.readableBytes() < length + 4) {
                    // 还原读指针
                    buffer.readerIndex(beginReader);
                    return;
                }

                // 协议版本
                int version = buffer.readInt();
                // 命令码
                int cmd = buffer.readInt();
                // 扣除 版本 和 命令码的长度 8
                int contentLength = length - 8;
                // 读取data数据
                byte[] content = new byte[contentLength];
                buffer.readBytes(content);
                // 包尾
                if (buffer.readInt() == NettyDecoder.END_DATA) {
                    log.debug("找到包尾");
                    // 包数据操作
                    TestProtocol protocol = new TestProtocol();
                    protocol.setLength(length);
                    protocol.setVersion(version);
                    protocol.setCmd(cmd);
                    protocol.setContent(content);
                    out.add(protocol);
                }
                // 包尾不对
                else {
                    log.error("找不到到包尾");
                    buffer.readerIndex(beginReader + 1);
                }
            }
            // 长度不够
            else {
                break;
            }
        }
    }

}

 

posted @ 2022-01-21 10:04  整合侠  阅读(239)  评论(0编辑  收藏  举报