-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuf_frame.go
168 lines (133 loc) · 3.22 KB
/
buf_frame.go
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package buf
import (
"bufio"
"encoding/hex"
"errors"
"github.com/injoyai/base/bytes"
"github.com/injoyai/conv"
"time"
)
// Frame 通用分包配置,适用99%的协议
type Frame struct {
*StartEndFrame
*LenFrame
Timeout time.Duration //超时时间
}
func (this *Frame) ReadMessage(buf *bufio.Reader) ([]byte, error) {
interval := time.Millisecond
result := []byte(nil)
for {
b, err := buf.ReadByte()
if err != nil {
return nil, err
}
result = append(result, b)
//校验数据是否满足帧头帧尾
seFull, err := this.StartEndFrame.Check(&result)
if err != nil {
return nil, err
}
//校验数据长度
leFull, err := this.LenFrame.Check(result)
if err != nil {
return nil, err
}
//如果满足条件,则返回结果
if seFull && leFull && !(this.StartEndFrame == nil && this.LenFrame == nil) {
return result, nil
}
//未设置任何参数,读取全部数据
if (this.StartEndFrame == nil || seFull) &&
(this.LenFrame == nil || leFull) &&
this.Timeout == 0 && buf.Buffered() == 0 {
return result, nil
}
//根据超时时间结束读取
waitTime := time.Duration(0)
for buf.Buffered() == 0 && this.Timeout > 0 {
<-time.After(interval)
waitTime += interval
if waitTime >= this.Timeout {
return result, nil
}
}
}
}
type StartEndFrame struct {
Start, End []byte //帧头,帧尾
}
// Check 校验字节,响应数据完整性和错误
func (this *StartEndFrame) Check(bs *[]byte) (bool, error) {
//未设置
if this == nil {
return true, nil
}
// 长度,减少代码长度...
lenBs, lenStart, lenEnd := len(*bs), len(this.Start), len(this.End)
//设置了帧头
if lenStart > 0 {
if lenBs <= lenStart {
isStart := true
for i, b := range *bs {
if isStart {
if b != this.Start[i] {
isStart = false
}
}
if !isStart {
//寻找帧头
if b == this.Start[0] {
*bs = append((*bs)[:0], (*bs)[i:]...)
break
} else {
*bs = append((*bs)[:0], (*bs)[:0]...)
break
}
}
}
}
}
//基本数据长度不足
if lenBs < lenStart+lenEnd {
return false, nil
}
if lenEnd > 0 {
//帧尾不符合,等待读取新的数据
if hex.EncodeToString((*bs)[lenBs-lenEnd:]) != hex.EncodeToString(this.End) {
return false, nil
}
}
//未设置帧头,帧尾,任意数据皆满足条件
return true, nil
}
type LenFrame struct {
LittleEndian bool //支持大端小端(默认false,大端),暂不支持2143,3412...
LenStart, LenEnd uint //长度起始位置,长度结束位置
LenFixed int //固定增加长度
}
func (this *LenFrame) Check(bs []byte) (bool, error) {
//未设置
if this == nil {
return true, nil
}
//设置了错误的参数
if this.LenStart > this.LenEnd {
return false, errors.New("参数设置有误")
}
//数据还不满足条件
if len(bs) <= int(this.LenEnd) {
return false, nil
}
//获取数据总长度
lenBytes := bs[this.LenStart : this.LenEnd+1]
if this.LittleEndian {
lenBytes = bytes.Entity(lenBytes).Reverse()
}
length := conv.Int(lenBytes) + this.LenFixed
//数据异常,或设置的参数有误
if length < len(bs) {
return false, errors.New("数据长度过长")
}
//返回结果
return length == len(bs), nil
}