/
packet.go
122 lines (91 loc) · 2.37 KB
/
packet.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
package util
import (
"encoding/binary"
"errors"
"github.com/fangjie-luoxi/cellnet"
"github.com/fangjie-luoxi/cellnet/codec"
"io"
)
var (
ErrMaxPacket = errors.New("packet over size")
ErrMinPacket = errors.New("packet short size")
ErrShortMsgID = errors.New("short msgid")
)
const (
bodySize = 2 // 包体大小字段
msgIDSize = 2 // 消息ID字段
)
// 接收Length-Type-Value格式的封包流程
func RecvLTVPacket(reader io.Reader, maxPacketSize int) (msg interface{}, err error) {
// Size为uint16,占2字节
var sizeBuffer = make([]byte, bodySize)
// 持续读取Size直到读到为止
_, err = io.ReadFull(reader, sizeBuffer)
// 发生错误时返回
if err != nil {
return
}
if len(sizeBuffer) < bodySize {
return nil, ErrMinPacket
}
// 用小端格式读取Size
size := binary.LittleEndian.Uint16(sizeBuffer)
if maxPacketSize > 0 && int(size) >= maxPacketSize {
return nil, ErrMaxPacket
}
// 分配包体大小
body := make([]byte, size)
// 读取包体数据
_, err = io.ReadFull(reader, body)
// 发生错误时返回
if err != nil {
return
}
if len(body) < msgIDSize {
return nil, ErrShortMsgID
}
msgid := binary.LittleEndian.Uint16(body)
msgData := body[msgIDSize:]
// 将字节数组和消息ID用户解出消息
msg, _, err = codec.DecodeMessage(int(msgid), msgData)
if err != nil {
// TODO 接收错误时,返回消息
return nil, err
}
return
}
// 发送Length-Type-Value格式的封包流程
func SendLTVPacket(writer io.Writer, ctx cellnet.ContextSet, data interface{}) error {
var (
msgData []byte
msgID int
meta *cellnet.MessageMeta
)
switch m := data.(type) {
case *cellnet.RawPacket: // 发裸包
msgData = m.MsgData
msgID = m.MsgID
default: // 发普通编码包
var err error
// 将用户数据转换为字节数组和消息ID
msgData, meta, err = codec.EncodeMessage(data, ctx)
if err != nil {
return err
}
msgID = meta.ID
}
pkt := make([]byte, bodySize+msgIDSize+len(msgData))
// Length
binary.LittleEndian.PutUint16(pkt, uint16(msgIDSize+len(msgData)))
// Type
binary.LittleEndian.PutUint16(pkt[bodySize:], uint16(msgID))
// Value
copy(pkt[bodySize+msgIDSize:], msgData)
// 将数据写入Socket
err := WriteFull(writer, pkt)
// Codec中使用内存池时的释放位置
if meta != nil {
codec.FreeCodecResource(meta.Codec, msgData, ctx)
}
return err
}