mina接收数据的封包

来源:互联网 发布:淘宝店企业店铺流程 编辑:程序博客网 时间:2024/04/29 21:54

mina在做数据发送的时候通过通过过滤器来做数据的转换


ProtocolCodecFilter 用来在字节流和消息对象之间互相转换。当该过滤器接收到字节流的时候,需要首先判断消息的边界,然后把表示一条消息的字节提取出来,通过一定的逻辑转换成消息对象,再把消息对象往后传递,交给 I/O 处理器来执行业务逻辑。


在发送数据的时候,如果数据量大,是会分包发送的,同时mina的数据接收区有默认的大小限制,比如缓冲与为1024的话,那么当缓冲区满了就回进入decode来尝试解码,如果没有做协议长度的控制,就可能会丢失数据。这次项目就用到了mina,记录一些封包的经验。


一、协议如何定

1.固定长度的报文(长度固定为100),每次收满固定长度的报文就去解析,否则就等待数据

2.前N位放表明报文长度的数据,每次接收先读出报文长度,然后在读长度内容的数据

这里详细介绍下第2种,这里的报文长度也有一些区别,比如:前4字节表明一个byte和前4字节表明一个4位的字符串数字,是不同的概念

第一种:int用4字节表示,只要报文长度不大于MAXInt即可

报文发送方:

        //报文的原始内容        String str = "content";        int length = 365;                //转换报文长度为byte        byte[] len = new byte[4];        for (int i = 0; i < 4; i++) {            int offset = (len.length - 1 - i) * 8;            len[i] = (byte) ((length >>> offset) & 0xFF);        }                //获取长度+报文的内容byte        byte[] content = str.getBytes();        content = Utils.join(len, content);
解析这种报文可以使用:

        //判断数据是否接收完毕        if (in.prefixedDataAvailable(4)) {            //处理报文            decodeHandle(in, out);        } else {            //报文没有接受完毕,需要继续等待数据            return false;        }
注意:

使用 in.prefixedDataAvailable(4) 的时候一定要注意,这个方法只支持1、2、4三个参数类型

1对应short、2对应UnsignedShort、4对应int。其实一个int对应的报文还是很长了,基本上够用了


这次的报文通信机构使用的是第二种方法

所以也介绍下第二种方法的封包方法

报文发送方:

//报文的原始内容        String str = "content";        String length = "0365";        //获取长度+报文的内容byte        String content = length + str;        byte[] byteContent = content.getBytes();
解析这种报文可以使用:

//先标记当前buffer的位置        in.mark();        //判断当前buffer长度位是否发送过来        if (in.remaining() <= 4) {            return false;        }        // 有数据时,根据定义好的字节个数判断消息长度          byte[] sizeBytes = new byte[4];        in.get(sizeBytes);        // 报文长度        String lengthStr = new String(sizeBytes);        int size = Integer.valueOf(lengthStr);        // 判断报文        if (size <= in.remaining()) {            //报文接收完毕            return true;        }        // 由于in.get会改变in游标的位置,所以reset到初始位置,也可以in.position(in.markValue());        in.reset();        return false;


CumulativeProtocolDecoder就是专门实现封包的

它会一直递归读取数据,每次递归中会执行doEncode方法, 在子类的doEncode方法中,我们可以根据我们的协议来判断数据是否接收够了(所以每次循环的时候要保证游标不转移)。