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() ; 
 | 
        } 
 | 
    } 
 | 
  
 | 
} 
 |