mina接收数据的封包

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方法中,我们可以根据我们的协议来判断数据是否接收够了(所以每次循环的时候要保证游标不转移)。

你可能感兴趣的:(String,buffer,Mina,byte)