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);
        }
    }
Netty自定义数据包协议的更多相关文章
- 基于Netty的RPC架构学习笔记(十):自定义数据包协议
		
文章目录 数据包简介 粘包.分包现象 数据包格式 举个
 - IM通信协议逆向分析、Wireshark自定义数据包格式解析插件编程学习
		
相关学习资料 http://hi.baidu.com/hucyuansheng/item/bf2bfddefd1ee70ad68ed04d http://en.wikipedia.org/wiki/I ...
 - 在dubbo的一端,看Netty处理数据包,揭网络传输原理
		
如今,我们想要开发一个网络应用,那是相当地方便.不过就是引入一个框架,然后设置些参数,然后写写业务代码就搞定了. 写业务代码自然很重要,但是你知道: 你的数据是怎么来的吗?通过网络传输过来的呗. 你知 ...
 - WebSocket数据包协议详解
		
其实我一直想不明白HTML5包装个应用层办议作为Socket通过基础目的是为了什么,其实直接支持Socket tcp相对来说更加简单灵活.既然标准已经制定而浏览器也支持那对于我们开发者来说只能用的分. ...
 - 【求助】NdisSend,自定义数据包发送失败?
		
做ndis hook的时候,自定义了一个数据包,包结构应该没有问题,填充NDIS_PACKET结构是这样的,先初始化: NdisAllocatePacketPool(&nStat ...
 - TCP/IP网络编程之数据包协议
		
一.概要 在了解了网络字节序之后,接下来就是要讲最最重点的消息协议.数据包是什么呢,数据包可以理解为两个人讲电话说的每一句话的内容.通过大家约定好的方式去理解.达到只有接听电话两个人才懂的东西.在程序 ...
 - asp.net core中遇到需要自定义数据包解密方法的时候
		
最近将公司的项目用.netcore重写, 服务的http外部接口部分收发消息是DES加解密的, 那么在asp.net core mvc的action处理之前需要加入解密这个步骤. 我第一想到的是用fi ...
 - 示例:Netty 处理 TCP数据分包协议
		
一个.Netty解决TCP协议的数据分包的想法 我们知道通过TCP协议发送接收数据时,假设数据过大.接收到的数据会是分包的.比方: ...
 - 如何实现自定义sk_buff数据包并提交协议栈
		
目录 一.自定义数据包的封装流程 1. 分配skb 2.初始定位(skb_reserve) 3.拷贝数据(skb_push / skb_pull / skb_put / ) 4.设置传输层头部 5.设 ...
 
随机推荐
- 一个类中域(field)的首字母不要大写
			
首先这种写法不规范, 其次,至少在AJAX交互的情况下, 如果首字母大写,会无法与前端相同名称的JSON属性相绑定. 如 data:{'Name':'2017-10-19'} public NameI ...
 - properties的编码问题
			
1.在eclipse中,如果不专门设置,properties文件的编码是ISO-8859-1,最好将其改为UTF-8 2.当properties文件的编码改为UTF-8还不够,Spring的conte ...
 - P2831 愤怒的小鸟——状压
			
P2831 愤怒的小鸟 抛物线过原点,只要再找两个就能确定抛物线: 处理出两两之间的抛物线能过哪些点,状态压缩: 但是直接枚举每一条抛物线常数太大会T,所以我们需要预处理一个low_bit表示当前状态 ...
 - zabbix (11) 监控TCP连接数
			
对TCP的监控可以采用ss.netstat./proc/net/tcp这三个不同的方案来实现.其中ss是最快的 (1)ss命令 [root@manager1 script_py ::]#time ss ...
 - 在OpenFOAM中做用户自定义库——编译library【转载】
			
转载自:http://openfoam.blog.sohu.com/22041538.html OpenFOAM自己提供的标准类都是以库的形式提供的,并且利用头文件给出了库的应用接口.这样一来,用户的 ...
 - CSS Pixel 和 Device pixels
			
Web developers need CSS pixels, that is, the pixels that are used in CSS declarations such as " ...
 - Spring学习随笔(1):为什么要使用Spring
			
寒冷的冬天,一周两节课,掏出买了一年没翻过的<Spring实战>. 刚刚接触spring的我对它还不是很熟悉,对各种知识的认知也比较浅薄,但我会学习的过程通过随笔记录下来,监督自己学下去. ...
 - Linux 一条命令杀死占用端口的所有进程
			
Linux 一条命令杀死占用端口的所有进程 2018年05月28日 19:43:05 gq97 阅读数 7655更多 分类专栏: Linux 版权声明:本文为博主原创文章,遵循CC 4.0 BY- ...
 - SQL-W3School-总结:SQL 快速参考
			
ylbtech-SQL-W3School-总结:SQL 快速参考 1.返回顶部 1. 来自 W3School 的 SQL 快速参考.可以打印它,以备日常使用. SQL 语句 语句 语法 AND / O ...
 - Error setting null for parameter #10 with JdbcType
			
转: Error setting null for parameter #10 with JdbcType OTHER . 2014年02月23日 11:00:33 厚积 阅读数 58535 my ...