liurunyu
2024-11-08 04779efe2410fb0df1ff983b26384d56471b85cf
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
126
127
128
129
130
package com.dy.common.mw.protocol.p206V2;
 
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;
 
 
@AnnotationPrefixedDataAvailable(
        enable = true,
        protocolName = ProtocolConstantV206V2.protocolName,
        priority = ProtocolConstantV206V2.priority,
        onLineDataMinLength = ProtocolConstantV206V2.onLineDataMinLength,
        headMinLength = ProtocolConstantV206V2.headMinLength)
@SuppressWarnings("unused")
public class PrefixedDataAvailableV2 implements PrefixedDataAvailable {
 
    private static final Logger log = LogManager.getLogger(PrefixedDataAvailableV2.class) ;
    
    private static final String protocolName = ProtocolConstantV206V2.protocolName ;
 
 
    /**
     * 分析上线数据(网络连接后第一包数据)是否可获得
     * @param in IoBuffer
     * @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 IoBuffer
     * @param remain  剩余
     * @param minDataLength 最小数据长度
     * @param maxDataLength 最大数据长度
     * @return PrefixedDataAvailableStatus
     * @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 byte[]
     * @param minDataLength 最小数据长度
     * @param maxDataLength 最大数据长度
     * @return PrefixedDataAvailableStatus
     * @throws Exception 异常
     */
    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) ;
        }
 
        
        CommonV2 parseCommon = new CommonV2();
        Boolean[] isThisProtocolData = parseCommon.isThisProtocolHead(preByte) ;
        if(isThisProtocolData == null || isThisProtocolData.length != 2 || !isThisProtocolData[0].booleanValue()){
            //不是本协议数据
            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) ;
        }else if(remain > dataLen){
            String headHex = ByteUtil.bytes2Hex(preByte, true) ;
            log.warn("收到数据之帧前部:" + headHex + ",但发生粘包现象。") ;
            return new PrefixedDataAvailableStatus().adjoined(dataLen) ;
        }else{
            // remain < dataLen
            String headHex = ByteUtil.bytes2Hex(preByte, true) ;
            log.warn("收到数据之帧前部:" + headHex + ",但发生断包现象。") ;
            return new PrefixedDataAvailableStatus().breaked() ;
        }
    }
 
}