liurunyu
2023-11-18 c1ddfd71223c1a7d704b6f21b669fbfcb37adc82
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.dy.common.mw.protocol.pMeterV1_0_1;
 
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 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;
 
 
@AnnotationPrefixedDataAvailable(
        protocolName = ProtocolConstantV1_0_1.protocolName,
        priority = ProtocolConstantV1_0_1.priority,
        onLineDataMinLength = ProtocolConstantV1_0_1.onLineDataMinLength,
        headMinLength = ProtocolConstantV1_0_1.headMinLength) 
public class PrefixedDataAvailableV1_0_1  implements PrefixedDataAvailable {
 
    private static Logger log = LogManager.getLogger(PrefixedDataAvailableV1_0_1.class) ;
    
    private static String protocolName = ProtocolConstantV1_0_1.protocolName ;
 
 
    /**
     * 分析上线数据(网络连接后第一包数据)是否可获得
     * @param in
     * @param remain 一定时大于0的数据
     * @param minDataLength 最小数据长度
     * @param maxDataLength 最大数据长度,达到或超过此长度,认为是垃圾数据。例如:数据头部是正确的,但合法数据结尾总不出现,认为此数据垃圾数据
     * @return 不是本协议数据时返回空
     * @throws Exception
     */
    public PrefixedDataAvailableStatus forOnLine(IoBuffer in, 
            int remain,
            int minDataLength, //对应ProtocolConstantV2_0.onLineDataMinLength
            int maxDataLength //对应ProtocolConstant.errorMaxLength
            ) throws Exception {
        
        int oldPosition = in.position() ;
        byte[] preByte = new byte[remain];
        in.get(preByte) ;
        //in.position(0) ;//错误用法,如果发生粘包数据,将会死循环
        in.position(oldPosition) ;
 
        return this.doForData(preByte, minDataLength, maxDataLength) ;
    }
 
    /**
     * 分析上线后(网络连接后非第一包数据)是否可获得
     * @param in
     * @param protocolConf Rtu配置
     * @param maxDataLength
     * @return
     * @throws Exception
     */
    @Override
    public PrefixedDataAvailableStatus forUpData(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(preByte, minDataLength, maxDataLength) ;
 
    }
    /**
     * 进行判断
     * @param preByte
     * @param maxDataLength
     * @return
     */
    private PrefixedDataAvailableStatus doForData(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_0_1 parseCommon = new CommonV1_0_1();
        boolean isThisProtocolData = parseCommon.isThisProtocolHead(preByte) ;
 
        if(!isThisProtocolData){
            //不是本协议数据
            return null ;
        }
 
        Integer dataLen = parseCommon.parseDataLen(preByte) ;
        
        String headHex = ByteUtil.bytes2Hex(preByte, true) ;
        
        if(dataLen == null){
            throw new BufferDataException("收到数据之帧前部:" + headHex + ",但严重错误,在进行断包与粘包检查时,未能得到数据帧的长度。");
        }
        
        if (dataLen <= 0 || dataLen > maxDataLength) {
            throw new BufferDataException("收到数据之帧前部:" + headHex + ",但严重错误,在进行断包与粘包检查时,数据帧的长度(" + dataLen + ")超出合法范围。");
        }
        
        if(remain == dataLen){
            //不断不粘
            return new PrefixedDataAvailableStatus().completed(dataLen) ;
        }else if(remain > dataLen){
            log.warn("收到数据之帧前部:" + headHex + ",但发生粘包现象。") ;
            return new PrefixedDataAvailableStatus().adjoined(dataLen) ;
        }else{
            // remain < dataLen
            log.warn("收到数据之帧前部:" + headHex + ",但发生断包现象。") ;
            return new PrefixedDataAvailableStatus().breaked() ;
        }
    }
 
}