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

被折叠的 条评论
为什么被折叠?



