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
mina自定义编解码相关推荐
- Netty常用招式——ChannelHandler与编解码
本文是Netty系列第8篇 上一篇文章我们深入学习了Netty逻辑架构中的核心组件ChannelHandler和ChannelPipeline,并介绍了它在日常开发使用中的最佳实践.文中也提到了,Ch ...
- Dubbo篇:基于Netty实现Dubbo协议编解码源码分析
Dubbo协议解析 Dubbo协议设计参考了TCP/IP协议,包括协议头和协议体两部分.16字节报文头主要携带了魔法数(0xdabb,用于分割两个不同请求),以及当前请求报文是否是Request.Re ...
- 【Apache Mina2.0开发之二】自定义实现Server/Client端的编解码工厂(自定义编码与解码器)!...
本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/apache-mina/831.html ☞ ...
- Mina Codec Filter对应协议实现编解码处理
原文地址:Mina Filter(Apache Mina user guide Chapter 9 Codec Filter) 本教程试图解释为什么以及如何使用ProtocolCodecFilter. ...
- 如何将ZCU106例程移植到自定义单板上(6)-测试文件编解码
软硬件系统构建好之后,VCU可以正常工作了.可以在VCU软件堆栈的不同层次上对VCU进行编解码,下面介绍一下使用VCU控制软件如何进行编解码. 1 H.264编码 编码指令:ctrlsw_encode ...
- HTTP测试、常用编解码转换工具
2019独角兽企业重金招聘Python工程师标准>>> Web/HTTP开发常用工具 http://www.24zhutian.com/download/HttpDebuger.ex ...
- Emoji表情编解码库XXL-EMOJI
2019独角兽企业重金招聘Python工程师标准>>> <Emoji表情编解码库XXL-EMOJI> 一.简介 1.1 概述 XXL-EMOJI 是一个灵活可扩展的Emo ...
- 解析rtcm32报文工具_RTCM32编解码中的一些概念及相关文献阅读
1. IODC和 IODE -- 导航电文相关.iode/iodc是在GPS系统的ICD2中定义的参数,iode指星历数据事件,iodc指星钟数据事件. IOD 是 issue of data ,数 ...
- Netty实战 IM即时通讯系统(八)服务端和客户端通信协议编解码
Netty实战 IM即时通讯系统(八)服务端和客户端通信协议编解码 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 客户端启动流程 实战: 客户端和服务端双向通信 数 ...
最新文章
- iOS-UIButton防止重复点击(三种办法)
- 远程连接Windows服务器
- git / 如何将其他分支的某些 commit 合并到当前分支中?
- android media_rw sdcard_rw,大约Android 了解权限管理
- Dijkstra的理解和实现
- PE 学习之路 —— 区块表
- 函数dup和dup2
- 总结div里面水平垂直居中的实现方法
- 130 个相见恨晚的超实用网站,一次性分享出来,十倍提高工作效率
- 把mdb文件导入SQL Server 软件的解决方法
- PIC单片机应用开发实践教程(四): MPLAB X IDE Debug
- 详解SSTI模板注入
- ISE如何生成msc文件,并写入flash中
- C语言编程编制职工档案管理程序,C语言课程设计--职工档案及简明信息生成.doc...
- 上传附件格式限制与内容校验
- Liunx配置yum源与本地配置yum源
- R语言 - 安装R及RStudio(Linux、Windows双重记录)
- 利用githubpages创建你的个人博客
- 深度学习--识别(四小人)人物图像
- 前复权是从今天的价格倒推 后复权是从上市价格前推 不复权就是原始K线。...
热门文章
- 如何购买腾讯云服务器?腾讯云服务器购买教程
- 评论回复功能 asp.net_微信重大更新!公众号推送时间线打乱+7大新功能上线!怎么玩?...
- html5新标签 figure 和 figcaption
- CSS -- 实现DIV层背景颜色渐变 (兼容IE 火狐 谷歌浏览器)
- 处女座与小姐姐(三)
- linux安装liinuxrar教程,linux操作系统下RAR的安装和使用
- js学习笔记----JavaScript中DOM扩展的那些事
- 艾媒:ofo用户份额领先摩拜超六成 每10辆共享单车7辆小黄车
- 程序员如何掌握计算机英语(转)
- js基本概念(上)之数据类型