mina框架CumulativeProtocolDecoder.doDecode方法浅析
来源:互联网 发布:淘宝four loko是真的嘛 编辑:程序博客网 时间:2024/05/19 22:58
测试说明
注释代码37行,打开38行。
服务器正常启动,确认设备连接正常。
设备为客户端,每3秒向服务器发送心跳
模拟网络短暂不通,多个包同时到达,粘包情况:
拔掉网线30秒,插入网线。
代码如下
package mina;import java.io.IOException;import java.net.InetSocketAddress;import java.util.Arrays;import org.apache.mina.core.buffer.IoBuffer;import org.apache.mina.core.service.IoHandlerAdapter;import org.apache.mina.core.session.AttributeKey;import org.apache.mina.core.session.IoSession;import org.apache.mina.filter.codec.CumulativeProtocolDecoder;import org.apache.mina.filter.codec.ProtocolCodecFilter;import org.apache.mina.filter.codec.ProtocolDecoderOutput;import org.apache.mina.filter.codec.ProtocolEncoderAdapter;import org.apache.mina.filter.codec.ProtocolEncoderOutput;import org.apache.mina.transport.socket.nio.NioSocketAcceptor;public class Test { public static void main(String[] args) throws IOException { final byte[] key = { (byte) 0xb9, (byte) 0xda, 0x5e, 0x15, 0x46, 0x57, (byte) 0xa7, (byte) 0x8d, (byte) 0x9d, (byte) 0x84, (byte) 0x90, (byte) 0xd8, (byte) 0xab, 0x00, (byte) 0x8c, (byte) 0xbc, (byte) 0xd3, 0x0a, (byte) 0xf7, (byte) 0xe4, 0x58, 0x05, (byte) 0xb8, (byte) 0xb3, 0x45, 0x06, (byte) 0xd0, 0x2c, 0x1e, (byte) 0x8f, (byte) 0xca, 0x3f }; NioSocketAcceptor acceptor = new NioSocketAcceptor(); acceptor.getFilterChain().addFirst("codec", new ProtocolCodecFilter(new ProtocolEncoderAdapter() { @Override public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception { System.out.println("编码:" + message); } }, new CumulativeProtocolDecoder() { @Override protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { System.out.println(); System.out.println("长度:" + in.limit()); System.out.println(); IoBuffer ioBuffer = getContext(session).getIoBuffer(); //IoBuffer ioBuffer = IoBuffer.allocate(100).setAutoExpand(true); while (in.hasRemaining()) { byte b = in.get(); ioBuffer.put(b); System.out.print("【"+b+"】"); if (b != 0x03 && b != 0x04) { continue; } byte[] array = ioBuffer.array(); if (array[0] != 0x02) { System.out.println(); System.out.println("======================================="); System.out.println("未知包" + ByteUtil.toHexStr(array)); System.out.println("======================================="); throw new RuntimeException("================未知包================"); } array = Arrays.copyOfRange(array, 1, ioBuffer.position() - 2); int temp1 = array.length / 32; int temp2 = array.length % 32; for (int i = 0; i < temp1; i++) { for (int j = 0; j < 32; j++) { array[i * 32 + j] ^= key[j]; } } for (int j = 0; j < temp2; j++) { array[temp1 * 32 + j] ^= key[j]; } System.out.println(""); System.out.println("======================================="); System.out.println("解析到包:" + new String(array)); System.out.println("======================================="); out.write(new String(array)); ioBuffer.clear(); System.out.println("返回true"); return true; } System.out.println("返回false"); return false; } private final AttributeKey CONTEXT = new AttributeKey(getClass(), "context"); public Context getContext(IoSession session) { Context ctx = (Context) session.getAttribute(CONTEXT); if (ctx == null) { ctx = new Context(); session.setAttribute(CONTEXT, ctx); } return ctx; } class Context { private IoBuffer ioBuffer = IoBuffer.allocate(100).setAutoExpand(true); public IoBuffer getIoBuffer() { return ioBuffer; } } })); acceptor.setHandler(new IoHandlerAdapter() { @Override public void messageReceived(IoSession session, Object message) throws Exception { super.messageReceived(session, message); } }); acceptor.bind(new InetSocketAddress(3333)); }}
打印如下
长度:53【2】【-35】【-65】【40】【124】【37】【50】【-99】【-18】【-8】【-80】【-95】【-71】【-101】【53】【-24】【-100】【-70】【110】【-51】【-44】【120】【102】【-43】【-41】【127】【50】【-32】【20】【62】【-7】【-85】【83】【-52】【-65】【100】【119】【35】【54】【-45】【-13】【-29】【-92】【-4】【-67】【-59】【103】【-8】【-44】【-23】【61】【0】【3】=======================================解析到包:device:ce41a05d id:0 cmd:408 value:beat~~ length:7=======================================返回true长度:256【2】【-35】【-65】【40】【124】【37】【50】【-99】【-18】【-8】【-80】【-95】【-71】【-101】【53】【-24】【-100】【-70】【110】【-51】【-44】【120】【102】【-43】【-41】【127】【50】【-32】【20】【62】【-7】【-85】【83】【-52】【-65】【100】【119】【35】【54】【-45】【-13】【-29】【-92】【-4】【-67】【-59】【103】【-8】【-44】【-23】【61】【0】【3】=======================================解析到包:device:ce41a05d id:0 cmd:408 value:beat~~ length:7=======================================返回true长度:256【2】【-35】【-65】【40】【124】【37】【50】【-99】【-18】【-8】【-80】【-95】【-71】【-101】【53】【-24】【-100】【-70】【110】【-51】【-44】【120】【102】【-43】【-41】【127】【50】【-32】【20】【62】【-7】【-85】【83】【-52】【-65】【100】【119】【35】【54】【-45】【-13】【-29】【-92】【-4】【-67】【-59】【103】【-8】【-44】【-23】【61】【0】【3】=======================================解析到包:device:ce41a05d id:0 cmd:408 value:beat~~ length:7=======================================返回true长度:256【2】【-35】【-65】【40】【124】【37】【50】【-99】【-18】【-8】【-80】【-95】【-71】【-101】【53】【-24】【-100】【-70】【110】【-51】【-44】【120】【102】【-43】【-41】【127】【50】【-32】【20】【62】【-7】【-85】【83】【-52】【-65】【100】【119】【35】【54】【-45】【-13】【-29】【-92】【-4】【-67】【-59】【103】【-8】【-44】【-23】【61】【0】【3】=======================================解析到包:device:ce41a05d id:0 cmd:408 value:beat~~ length:7=======================================返回true长度:256【2】【-35】【-65】【40】【124】【37】【50】【-99】【-18】【-8】【-80】【-95】【-71】【-101】【53】【-24】【-100】【-70】【110】【-51】【-44】【120】【102】【-43】【-41】【127】【50】【-32】【20】【62】【-7】【-85】【83】【-52】【-65】【100】【119】【35】【54】【-45】【-13】【-29】【-92】【-4】【-67】【-59】【103】【-8】【-44】【-23】【61】【0】【3】=======================================解析到包:device:ce41a05d id:0 cmd:408 value:beat~~ length:7=======================================返回true长度:256【2】【-35】【-65】【40】【124】【37】【50】【-99】【-18】【-8】【-80】【-95】【-71】【-101】【53】【-24】【-100】【-70】【110】【-51】【-44】【120】【102】【-43】【-41】【127】【50】【-32】【20】【62】【-7】【-85】【83】【-52】【-65】【100】【119】【35】【54】【-45】【-13】【-29】【-92】【-4】返回false长度:433【-67】【-59】【103】【-8】【-44】【-23】【61】【0】【3】=======================================未知包BD,C5,67,F8,D4,E9,3D,00,03,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00=======================================长度:53【2】【-35】【-65】【40】【124】【37】【50】【-99】【-18】【-8】【-80】【-95】【-71】【-101】【53】【-24】【-100】【-70】【110】【-51】【-44】【120】【102】【-43】【-41】【127】【50】【-32】【20】【62】【-7】【-85】【83】【-52】【-65】【100】【119】【35】【54】【-45】【-13】【-29】【-92】【-4】【-67】【-59】【103】【-8】【-44】【-23】【61】【0】【3】=======================================解析到包:device:ce41a05d id:0 cmd:408 value:beat~~ length:7=======================================返回true
解释
插入网线后,不打印日志。(模拟的,有时是马上就打印)
大约20秒后,瞬间收到5、60行日志。
一个心跳包已0x02开头、已0x03结尾,长度为53。
日志第2行:长度为53,表示这个包正常
日志第10行:长度为256,说明IoBuffer in一次从缓存读取256个字节,是4个心跳包加半个心跳包的长度。
代码:
41行,每次取一个字节
42行,保存字节到ioBuffer
45行,如果不是取到一个完整的包,继续保存字节到ioBuffer
60行,解码数据
79行,返回true
上级代码
protected CumulativeProtocolDecoder() { } public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { if (!session.getTransportMetadata().hasFragmentation()) { while (in.hasRemaining()) { /** 当前读取到in的53的位置,还有剩余字节(共256),并且doDecode返回的true,则继续执行doDecode。CumulativeProtocolDecoder.decode(..)的上层为同步,所以这个没循环完,就算缓存还有新数据,也需要等待decode方法执行完才可以。上层代码: synchronized (session) { decoder.decode(session, in, decoderOut); } */ if (!doDecode(session, in, out)) { break; } } return; } boolean usingSessionBuffer = true; IoBuffer buf = (IoBuffer) session.getAttribute(BUFFER);
日志第18行:
从in的256的53位置继续读取53个字节,继续返回true
日志第26行:
从in的256的106位置继续读取53个字节,继续返回true
日志第34行:
从in的256的159位置继续读取53个字节,继续返回true
日志第34行:
从in的256的212位置继续读取53个字节,继续返回true
日志第42行:
从in的256的212位置继续读取44个字节,返回false
CumulativeProtocolDecoder() {
}
public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
if (!session.getTransportMetadata().hasFragmentation()) {
while (in.hasRemaining()) {
/**
返回false,表示本方法执行完毕。如果有新包则在执行。
*/
if (!doDecode(session, in, out)) {
break;
}
}
return;
}
日志第42行:
本次长度433(上次心跳包的9个字节+新的8个心跳包的长度)
test.java.38行又重新创建的IoBuffer,通过0x03截取的时候,取到的是9个字节的长度。所以需要把IoBuffer放入session中,就可以连接上次取到的包加本次的9个字节,组合成一个完成的包。
- mina框架CumulativeProtocolDecoder.doDecode方法浅析
- Mina 粘包断包解码 CumulativeProtocolDecoder 源码解读
- MINA源码分析---CumulativeProtocolDecoder协议解码器
- Apache Mina CumulativeProtocolDecoder 内部函数说明
- 浅析Mina
- MINA框架
- MINA框架
- MINA 框架
- mina框架
- mina框架
- mina框架分析:mina Filter
- MINA框架使用总结
- 读mina框架源码
- mina框架源代码研究
- MINA框架使用总结
- MINA框架概述
- MINA网络框架
- MINA 框架简介
- 机器学习-推荐系统
- 工作总结
- linux_1.0_环境配置
- HDOJ2032(杨辉三角)
- python基础笔记2-字符串处理函数
- mina框架CumulativeProtocolDecoder.doDecode方法浅析
- 三维计算机视觉(一)--点云处理综述
- WSL会阻碍自由软件的发展吗?开源闭源如何共存?
- 12 JSP学习笔记
- 关于远程连接外网数据库 的解决方案
- Timus 1003. Parity 【并查集】
- Git远程操作详解(基础)
- 个人QQ 2603336800
- Html.fromHtml()中Html.TagHandler()的使用