package com.dy.common.mw.protocol.p206V1; import com.dy.common.mw.channel.tcp.PrefixedDataAvailableStatus; import com.dy.common.mw.protocol.AnnotationPrefixedDataAvailable; import com.dy.common.mw.protocol.PrefixedDataAvailable; import com.dy.common.util.ByteUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.mina.core.buffer.BufferDataException; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; @AnnotationPrefixedDataAvailable( enable = true, protocolName = ProtocolConstantV206V1.protocolName, protocolVersion = ProtocolConstantV206V1.protocolVer, priority = ProtocolConstantV206V1.priority, onLineDataMinLength = ProtocolConstantV206V1.onLineDataMinLength, headMinLength = ProtocolConstantV206V1.headMinLength) @SuppressWarnings("unused") public class PrefixedDataAvailableV1 implements PrefixedDataAvailable { private static final Logger log = LogManager.getLogger(PrefixedDataAvailableV1.class) ; private static final String protocolName = ProtocolConstantV206V1.protocolName ; private static final short protocolVersion = ProtocolConstantV206V1.protocolVer ; /** * 分析上线数据(网络连接后第一包数据)是否可获得 * @param in IoBuffer * @param remain 一定时大于0的数据 * @param minDataLength 最小数据长度 * @param maxDataLength 最大数据长度,达到或超过此长度,认为是垃圾数据。例如:数据头部是正确的,但合法数据结尾总不出现,认为此数据垃圾数据 * @return 不是本协议数据时返回空 * @throws Exception 异常 */ public PrefixedDataAvailableStatus forOnLine(IoSession ioSession, IoBuffer in, int remain, int minDataLength, int maxDataLength ) throws Exception { int oldPosition = in.position() ; byte[] preByte = new byte[remain]; in.get(preByte) ; //in.position(0) ;//错误用法,如果发生粘包数据,将会死循环 in.position(oldPosition) ; return this.doForData(ioSession, preByte, minDataLength, maxDataLength) ; } /** * 分析上线后(网络连接后非第一包数据)是否可获得 * @param in IoBuffer * @param remain 剩余 * @param minDataLength 最小数据长度 * @param maxDataLength 最大数据长度 * @return PrefixedDataAvailableStatus * @throws Exception 异常 */ @Override public PrefixedDataAvailableStatus forUpData(IoSession ioSession, IoBuffer in, int remain, int minDataLength, int maxDataLength) throws Exception { int oldPosition = in.position() ; byte[] preByte = new byte[remain]; in.get(preByte) ; //in.position(0) ;//错误用法,如果发生粘包数据,将会死循环 in.position(oldPosition) ; return this.doForData(ioSession, preByte, minDataLength, maxDataLength) ; } /** * 进行判断 * @param ioSession ioSession * @param preByte byte[] * @param minDataLength 最小数据长度 * @param maxDataLength 最大数据长度 * @return PrefixedDataAvailableStatus * @throws Exception 异常 */ private PrefixedDataAvailableStatus doForData(IoSession ioSession, byte[] preByte, int minDataLength, int maxDataLength) throws Exception{ int remain = preByte.length ; if (remain < minDataLength) { log.warn("基于协议(" + protocolName + ")判断数据头部发生断包现象。") ; return new PrefixedDataAvailableStatus().breaked() ; } if(remain >= maxDataLength){ //超出了最大长度限制,例如:数据头部是正确的,但合法数据结尾总不出现,认为此数据垃圾数据 return new PrefixedDataAvailableStatus().rubbish(remain) ; } CommonV1 parseCommon = new CommonV1(); Boolean[] isThisProtocolData = parseCommon.isThisProtocolHead(preByte) ; if(isThisProtocolData == null || isThisProtocolData.length != 2 || !isThisProtocolData[0].booleanValue()){ //不是本RTU的协议数据 return null ; } Integer dataLen = parseCommon.parseFrameLen(preByte, isThisProtocolData[1]) ; if(dataLen == null){ String headHex = ByteUtil.bytes2Hex(preByte, true) ; throw new BufferDataException("收到数据之帧前部:" + headHex + ",但严重错误,在进行断包与粘包检查时,未能得到数据帧的长度。"); } if (dataLen <= 0 || dataLen > maxDataLength) { String headHex = ByteUtil.bytes2Hex(preByte, true) ; throw new BufferDataException("收到数据之帧前部:" + headHex + ",但严重错误,在进行断包与粘包检查时,数据帧的长度(" + dataLen + ")超出合法范围。"); } if(remain == dataLen){ //不断不粘 return new PrefixedDataAvailableStatus().completed(dataLen, protocolName, protocolVersion) ; }else if(remain > dataLen){ String headHex = ByteUtil.bytes2Hex(preByte, true) ; log.warn("收到数据之帧前部:" + headHex + ",但发生粘包现象。") ; return new PrefixedDataAvailableStatus().adjoined(dataLen, protocolName, protocolVersion) ; }else{ // remain < dataLen String headHex = ByteUtil.bytes2Hex(preByte, true) ; log.warn("收到数据之帧前部:" + headHex + ",但发生断包现象。") ; return new PrefixedDataAvailableStatus().breaked() ; } } }