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编解码来说,总的就是根据协议,在信息发送之前进行编码,在信息接收到后进行验证,解码。

转载于:https://www.cnblogs.com/yanghuiping/p/4108063.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值