zoukankan      html  css  js  c++  java
  • mina自定义编解码

    Mina自定义编解码

    Mina初了自己定义的字符编码外,用户还可以根据自己的协议自定义编解码。由于mina是基于IoFilter,也就是通过IoFilter拦截和过滤IO中的各种信息。因此对于编码而言,也就是我们把信息通过mina进行传递前,必须要根据相关的传输协议对我们传输的信息进行编码,编码后会把编码的信息通过mina进行传递。可以把编码理解为mina进行数据传输前IoFilter的最后一项处理。对于解码来说,是mina得到数据后的首次处理。即IoFilter后的首次数据处理。

    自定义编码在mina中的引用代码一般如下:

    DefaultIoFilterChainBuilder filterChain = connector.getFilterChain();

    ProtocolCodecFilter filter = new ProtocolCodecFilter(new TianhuiEncoder(), new TianhuiCumulativeHandler());

    filterChain.addLast("codec", filter);

    1.自定义编码

    自定义编码类 TianhuiEncoder.java 需要继承 ProtocolEncoderAdapter.java ,覆盖ProtocolEncoderAdapter.java类的encode(IoSession session,Object obj,ProtocolEncoderOuput o)方法。主要实现步骤是:

    A. 把对象obj根据协议转换为byte[] rst数组。

    B. 通过ProtocolEncoderOuput把byte输出出去。即:o.write(IoBuffer.wrap(rst));

    实例编码:

    编码的协议如下:

    指令

    长度

    用户

    地址

    信息内容

    校验和

    定位申请

    $DWSQ

    16

    bit

    24bit

    信息类别

    8bit

    高程数据和天线高

    32bit

    气压数据

    32bit

    入站频度

    16bit

    8

    bit

    通信申请

    $TXSQ

    16

    bit

    24bit

    信息类别

    8bit

    用户地址

    24bit

    电文长度

    16 bit

    是否应答

    8bit

    内容最长1680bit

    8 bit

                     

    现在编码“定位申请”。

    从协议上看,定位申请一共有22byte。$dwsq为5byte,长度1byte,用户地址为3byte,信息内容为12byte,校验和为1byte。因此需要:

    byte[] rst = new byte[22];

    主要的编码方法如下:

    public byte[] encode(){

            byte[] rst = new byte[22];

            TianHuiMessageUtil.setHeader(rst, getType(), userid, (long) 22);

            rst[10]=4;//信息类别

            TianHuiMessageUtil.genCheckNum(rst);

            return rst;

    }

    其中sentHeader方法如下:

    public static void setHeader(byte[] rst, TH_MSGTYPE thMsgType, long userid, long length) {

            rst[0] = (byte) 36;//$字符

            ByteUtils.setBytes(rst, TH_MSGTYPE.getType(thMsgType).getBytes(), 1);//DWSQ字符

            ByteUtils.setLong(length, rst, 5, 2);//根据协议,代表的为长度,从第5位开始,共2byte。

            ByteUtils.setLong(userid, rst, 7, 3);//和上面一样,用户地址,从第七位开始,共3byte。

    }

    其中setBytes方法如下:

    public static void setBytes(byte[] dst, byte[] src, int start) {

            if (src == null || src.length == 0){ return;}

            for (int i = 0, n = src.length; i < n; i++){

                dst[start + i] = src[i];

    }

    }

    其中setLong方法如下:

    public static void setLong(long value, byte[] data, int index, int length) {

            for (int i = length - 1; i >= 0; i--, value = value >> 8){

                data[index + i] = (byte) (value & 0xFF);

    }

    }

    其中genCheckNum方法是计算校验和进行添加。方法如下:

    public static void genCheckNum(byte[] data) {

            byte tmp = 36;

            for (int i = 1, n = data.length - 1; i < n; i++)

                tmp ^= data[i];

            data[data.length - 1] = tmp;

    }

    2.自定义解码

    自定义解码类为TianhuiCumulativeHandler.java,此类继承mina的CumulativeProtocolDecoder.java类,覆盖boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)方法。主要的实现是根据协议对信息进行验证。对验证通过返回true,验证失败舍弃信息。

    实例编码:

    解码协议:

    内容

    长度

    用户地址

    信息内容

    校验和

    定位信息

    $DWXX

    16

    bit

    24

    bit

    信息类别8bit

    查询地址

    24bit

    位置数据

    8 bit

    T 32bit

    L 32bit

    B32bit

    H 16bit

    ζH 6bit

    通信信息

    $TXXX

    16

    bit

    24

    bit

    信息

    类别

    8bit

    发信方地

    24bit

    发信时间

    电文长度

    16 bit

    电文内容最长1680bit

    CRC标志

    8 bit

    8 bit

    h

    8 bit

    M

    8bit

    反馈信息

    $FKXX

    16

    bit

    24

    bit

    反馈标志

    附加信息

    8 bit

    8bit

    32bit

                                       

    方法doDecode的主要实现如下所示:

    @Override

    protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception

    {

            return  handle(session, in, out);

    }

    其中handle是主要的实现方法, 主要实现如下:

    public boolean handle(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception{

            int start = in.position();

            LOGGER.info("recv:" + in.getHexDump());

            while (in.hasRemaining())

            {

                byte first = in.get();

                if (first == (byte) 36 && in.remaining() > 7)

                {

                    int messageStart = in.position();

                    byte[] header = new byte[6];

                    in.get(header);

                    int msgLength = (int) ByteUtils.getValue(header, 4, 2);

                    if (in.remaining() >= msgLength - 7 && msgLength < 500)

                    {

                        in.position(start);

                        byte[] bs = new byte[msgLength];

                        in.get(bs);

                        if (check(bs))

                        {

                            out.write(bs);

                            return in.remaining() > 0;

                        }

                        else in.position(messageStart);

                    }

                    else in.position(messageStart);

                }

            }

            in.position(start);

            return false;

    }

     

    public boolean check(byte[] data) {

        if (data.length < 2){

            return false;

    }

            byte tmp = 36;

            for (int i = 1, n = data.length - 1; i < n; i++)

                tmp ^= data[i];

            return data[data.length - 1] == tmp;

    }

    对于解码来说,主要的作用是解析成所要的对象。如下所示,把byte[] rst根据协议解析为位置定位对象。

    public AbsThMessage build(byte[] raw){

            userId = ByteUtils.getValue(raw, 7, 3);

            dstUserId = ByteUtils.getValue(raw, 11, 3);

            JDateTime tmptime = new JDateTime();

            tmptime.setHour(raw[14]);

            tmptime.setMinute(raw[15]);

            tmptime.setSecond(raw[16]);

            time=tmptime.convertToDate();

            lati=raw[18]+raw[19]/60.0+raw[20]/3600.0+raw[21]/36000.0;

            longi=raw[22]+raw[23]/60.0+raw[24]/3600.0+raw[25]/36000.0;

            h=(((raw[26]>>6)==0)?1:-1)+((63&raw[26])<<8)+raw[27];

            return this;

    }

    其中getValue方法如下:

    public static long getValue(byte[] data, int index, int length) {

            long result = 0;

            for (int i = 0; i < length; i++)

            {

                result = result << 8;

                result += (data[index + i] & 0xFF);

            }

            return result;

    }

    3.对于mina编解码来说,总的就是根据协议,在信息发送之前进行编码,在信息接收到后进行验证,解码。

  • 相关阅读:
    C# 9.0语法新特性【废弃,自用,无参考价值】
    0兆宽带年费过万,垄断坑企咋破
    筹划建立题目该如何作答?
    去重 sort -u
    大城市治理
    申论话题
    面试 思维
    成语
    人民日报怒批机关事业单位三大怪状
    留痕主义
  • 原文地址:https://www.cnblogs.com/yanghuiping/p/4108063.html
Copyright © 2011-2022 走看看